Reputation: 131
I have an array of questions and I want to get a non-reapting random one out of them. So for instance 5 questions, and if asked all i will simply start again. I would like to put it into an method (or something like that)
def askrandom
questions = ["A?", "B?" , "C?" , "D?"]
return #random question
end
The output should be something like
A? C? D? B? #all questions where asked once, so repeat
B? D? C? A? ...
Upvotes: 3
Views: 579
Reputation: 110725
def fire_away(questions)
@n = (@n || -1) + 1
@order = [*0...questions.size].shuffle if @n % questions.size == 0
questions[@order.shift]
end
q = ["A?", "B?" , "C?" , "D?"]
fire_away q #=> "D?"
fire_away q #=> "A?"
fire_away q #=> "C?"
fire_away q #=> "B?"
fire_away q #=> "B?"
fire_away q #=> "C?"
fire_away q #=> "A?"
fire_away q #=> "D?"
fire_away q #=> "A?"
fire_away q #=> "C?"
fire_away q #=> "B?"
fire_away q #=> "D?"
You may also need the method
def reset_questions
@n = nil
end
@fl00r suggested the following to avoid the need for instance variables that are visible within the class in which fire_away
is defined (and avoid the need for the method reset_questions
):
def fire_away(questions)
n = -1
order = nil
Proc.new do
n += 1
order = [*0...questions.size].shuffle if n % questions.size == 0
questions[order.shift]
end
end
iterator = fire_away ["A", "B", "C", "D"]
iterator.call #=> "C"
iterator.call #=> "A"
iterator.call #=> "B"
iterator.call #=> "D"
iterator.call #=> "D"
Another way would be to create a separate class (which is quite close to @fl00r's answer).
class Questions
def initialize(*questions)
@questions = questions
@n = -1
end
def next_question
@n += 1
@order = [*[email protected]].shuffle if @n % @questions.size == 0
@questions[@order.shift]
end
end
q = Questions.new("A?", "B?" , "C?" , "D?")
q.next_question #=> "C?"
q.next_question #=> "A?"
q.next_question #=> "D?"
q.next_question #=> "B?"
q.next_question #=> "B?"
Both of these modifications are clearly superior to my original answer.
Upvotes: 0
Reputation: 83680
It is very close to @Stefan's solution with a slightly changed idea.
class Questions
def initialize(array_of_questions)
@questions = array_of_questions
@nums ||= get_nums
end
def get_nums
([email protected]).to_a.shuffle
end
def get_num
@nums.pop or (@nums = get_nums).pop
end
def pick
@questions[get_num]
end
end
questions = Questions.new(["A", "B", "C", "D"])
10.times.map{ questions.pick }
#=> ["B", "D", "C", "A", "C", "A", "B", "D", "A", "B"]
Upvotes: 2
Reputation: 121010
Pure functional approach:
def ask(question)
question.tap { |q| puts "Asking question #{q}" }
end
def askrandom(asked = [], remaining = ["A?", "B?" , "C?" , "D?"].shuffle)
return asked if remaining.empty?
askrandom(asked << ask(remaining.pop), remaining)
end
Upvotes: 0
Reputation: 114218
To avoid repeating a question, you have to store the remaining questions somewhere, let's use an instance variable:
def initialize
@remaining_questions = []
end
And let's extract the questions into a method of its own:
def questions
["A?", "B?" , "C?" , "D?"]
end
Now, if @remaining_questions
is empty, you initialize it with a shuffled copy of questions
. Then, you simply remove (and return) the first item:
def ask_random
@remaining_questions = questions.shuffle if @remaining_questions.empty?
@remaining_questions.shift
end
Upvotes: 2
Reputation: 26
I usally create a new array and after random I append the value which just random if it does not exist in new array.
if you get a same output like last time, it means output was in a new array because you appended it.
Sorry about my silly English.
Upvotes: -1