Warning: file_get_contents(/data/phpspider/zhask/data//catemap/5/ruby/20.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Arrays 在ruby中获取数组的随机非重复元素_Arrays_Ruby_Random - Fatal编程技术网

Arrays 在ruby中获取数组的随机非重复元素

Arrays 在ruby中获取数组的随机非重复元素,arrays,ruby,random,Arrays,Ruby,Random,我有一系列的问题,我想从中得到一个不可重复的随机问题。举个例子,5个问题,如果全部问完,我会重新开始。我想把它变成一种方法(或类似的东西) 输出应该类似于 A?CDB#所有问题只问一次,请重复 B?DCA我通常创建一个新数组,在随机之后,如果新数组中不存在随机值,我会附加随机值。 如果您得到与上次相同的输出,则表示输出位于新数组中,因为您附加了它。 很抱歉我的愚蠢英语。为了避免重复一个问题,您必须将剩余的问题存储在某个位置,让我们使用一个实例变量: def initialize @remai

我有一系列的问题,我想从中得到一个不可重复的随机问题。举个例子,5个问题,如果全部问完,我会重新开始。我想把它变成一种方法(或类似的东西)

输出应该类似于

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?"