Arrays 在ruby中获取数组的随机非重复元素
我有一系列的问题,我想从中得到一个不可重复的随机问题。举个例子,5个问题,如果全部问完,我会重新开始。我想把它变成一种方法(或类似的东西) 输出应该类似于Arrays 在ruby中获取数组的随机非重复元素,arrays,ruby,random,Arrays,Ruby,Random,我有一系列的问题,我想从中得到一个不可重复的随机问题。举个例子,5个问题,如果全部问完,我会重新开始。我想把它变成一种方法(或类似的东西) 输出应该类似于 A?CDB#所有问题只问一次,请重复 B?DCA我通常创建一个新数组,在随机之后,如果新数组中不存在随机值,我会附加随机值。 如果您得到与上次相同的输出,则表示输出位于新数组中,因为您附加了它。 很抱歉我的愚蠢英语。为了避免重复一个问题,您必须将剩余的问题存储在某个位置,让我们使用一个实例变量: def initialize @remai
A?CDB#所有问题只问一次,请重复
B?DCA代码>我通常创建一个新数组,在随机之后,如果新数组中不存在随机值,我会附加随机值。
如果您得到与上次相同的输出,则表示输出位于新数组中,因为您附加了它。
很抱歉我的愚蠢英语。为了避免重复一个问题,您必须将剩余的问题存储在某个位置,让我们使用一个实例变量:
def initialize
@remaining_questions = []
end
让我们将这些问题提取到自己的方法中:
def questions
["A?", "B?" , "C?" , "D?"]
end
现在,如果@remaining_questions
为空,则使用questions
的无序副本对其进行初始化。然后,您只需删除(并返回)第一项:
def ask_random
@remaining_questions = questions.shuffle if @remaining_questions.empty?
@remaining_questions.shift
end
纯功能方法:
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
def提问(问题)
tap{q}放置“提问{q}”
结束
def askrandom(询问=[],剩余=[“A?”,“B?”,“C?”,“D?”]。随机播放)
返回询问是否剩余。是否为空?
askrandom(问这与@Stefan的解决方案非常接近,只是想法略有改变
class Questions
def initialize(array_of_questions)
@questions = array_of_questions
@nums ||= get_nums
end
def get_nums
(0...@questions.size).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"]
您可能还需要该方法
def reset_questions
@n = nil
end
@fl00r建议如下,以避免需要在定义了fire\u away
的类中可见的实例变量(并避免需要方法reset\u questions
):
另一种方法是创建一个单独的类(非常接近@fl00r的答案)
这两种修改都明显优于我的原始答案。如果你有一个巨大(或无限)的你无法在内存中加载的问题数量。然后你可以使用数论的一些技巧使你的选择足够随机。例如,任何n个连续的数字通过n的模提升到素数的幂,得到0到n-1的数字。哎呀,我撒了一点谎。素数不应该是偶数(aka 2)没有构造函数的shuffle
会不会让它少一点设计过度?@mudasobwa只工作一次,因为[]
是真实的。既然我们引入了一个类,它的生命周期可能很容易缩短为“新的”⇒ 问⇒ 需要新的调查问卷吗⇒ 创建新对象。无论如何,这是一个超出范围的实现设计问题。@mudasobwa我假设ask\u random
应该返回一个问题,并且您可以无限期地调用它。因此会产生开销。感谢Stefan和Holger,但不知怎的,这会导致未定义的方法为空?:NilClass(NoMethodError)`例外,当我尝试使用它时。它会增加三倍的操作成本,再加上它在有重复的阵列上失败。这是实现这一目标的最糟糕的方法。@ndn的人倾向于对他们不理解的解决方案投反对票,ruby社区对rails的丑陋有负面影响。@ndn我已经运行了代码,但输出不正确正如作者所期望的。我想这可能是原因。@fl00r OP清楚地指出“输出应该是这样的。”在这里使用OOP是一种过度杀伤力,几乎是一种代码味道。@mudasobwa是的,OP对他想要的东西有一个模糊的定义。我同意你的观点,OOP在很多情况下都是过度杀伤力,但无论如何,这是一个非常有争议的说法:)。我很好奇你为什么使用这种结构question.tap{q |puts“提问{q}”
代替简单的放置“提问{question}”“
。为什么在这里使用点击。我想说,这里有太多的全球国家。我将通过将状态包装到lambda/fiber/enumerator或某个类中来添加一些封装。一个副作用是,如果您将使用不同的输入重用您的方法:fire\u away(q1);开火(q2)
我的意思是@fl00r,非常好的建议!我以前从未见过这种技术。我来编辑。
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?"
def reset_questions
@n = nil
end
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"
class Questions
def initialize(*questions)
@questions = questions
@n = -1
end
def next_question
@n += 1
@order = [*0...@questions.size].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?"