如何在ruby中选择随机对,而不重复对

时间:2017-10-23 17:19:33

标签: arrays ruby

我想从数组中随机选择2个名字,为数组中的所有名称执行此操作,并确保没有人与同一个人联系两次。在每个人与对方一起合作之后,重新开始大循环。

我发现.sample方法可以随机从数组中提取2个名称。 [“Sander”, “Sjaak”, “Timo”, “Ernst”, “Floris”, “Wayne”, “Arno”, “Henk”, “Rob”].sample(2)

但是,如何确保第二天人们不会与同一个人合作?

2 个答案:

答案 0 :(得分:3)

这是棋手玩全部比赛的方式。它被称为"循环赛锦标赛"。 Wikipedia has an algorithm。可以预先对阵列进行洗牌。 这是维基百科文章的实现:

names = ["Sander", "Sjaak", "Timo", "Ernst", "Floris", "Wayne", "Arno", "Henk", "Rob"]

n = names.dup #n is going to be mutated, leave names intact
n << "Dummy" if n.size.odd?
fixed_name = n.shuffle!.pop

n.size.times do |i| #n.size is one less than the number of participants
  puts "round #{i+1}"
  two_rows = [[fixed_name]+n[0..n.size/2-1], n[n.size/2..-1].reverse]
  pairs = two_rows.transpose.shuffle # the shuffle is optional, just cosmetic
  pairs.each{|c| p c }
  n.rotate!
  puts
end

输出:

round 1
["Arno", "Floris"]
["Wayne", "Dummy"]
["Sander", "Sjaak"]
["Henk", "Rob"]
["Ernst", "Timo"]

round 2
["Wayne", "Sjaak"]
["Dummy", "Rob"]
["Ernst", "Arno"]
["Henk", "Floris"]
["Sander", "Timo"]

round 3
["Wayne", "Timo"]
["Henk", "Arno"]
["Rob", "Sjaak"]
["Ernst", "Sander"]
["Dummy", "Floris"]

round 4
["Wayne", "Sander"]
["Sjaak", "Floris"]
["Dummy", "Arno"]
["Rob", "Timo"]
["Ernst", "Henk"]

round 5
["Sjaak", "Arno"]
["Dummy", "Henk"]
["Floris", "Timo"]
["Rob", "Sander"]
["Ernst", "Wayne"]

round 6
["Ernst", "Dummy"]
["Timo", "Arno"]
["Rob", "Wayne"]
["Sjaak", "Henk"]
["Floris", "Sander"]

round 7
["Timo", "Henk"]
["Sjaak", "Dummy"]
["Floris", "Wayne"]
["Ernst", "Rob"]
["Arno", "Sander"]

round 8
["Ernst", "Sjaak"]
["Sander", "Henk"]
["Arno", "Wayne"]
["Floris", "Rob"]
["Timo", "Dummy"]

round 9
["Sander", "Dummy"]
["Ernst", "Floris"]
["Henk", "Wayne"]
["Arno", "Rob"]
["Timo", "Sjaak"]

答案 1 :(得分:1)

从一系列名称开始:

names = ["Sander", "Sjaak", "Timo", "Ernst", "Floris", "Wayne", "Arno", "Henk"]

你想要将它们混洗并成对分组:

shuffled = names.shuffle.each_slice(2).to_a
#=> [["Timo", "Sjaak"], ["Henk", "Arno"], ["Sander", "Ernst"], ["Wayne", "Floris"]] 

到目前为止看起来不错,但是这将是一个问题,因为顺序对数组很重要。例如,[&#34; Timo&#34;,&#34; Sjaak&#34;]被认为与[&#34; Sjaak&#34;,&#34; Timo&#34;]不同。我们可以通过将数组转换为集合来解决这个问题。在确定两个集合是否相等时,顺序并不重要。

shuffled = names.shuffleeach_slice(2).map { |group| Set.new(group) }
#=> [#<Set: {"Arno", "Wayne"}>, #<Set: {"Henk", "Timo"}>, #<Set: {"Ernst", "Floris"}>, #<Set: {"Sander", "Sjaak"}>] 

棘手的部分是确保每一天都没有重复。你可能有&#34;规则&#34;为了防止这种情况,但是你的算法将不再是随机的。确保完全随机性的唯一方法是检查重复和重新洗牌。我们假设您已将某一天的群组保存到yesterday,并且您想要一个新的群组。您可以执行以下操作:

loop do
  today = names.shuffle.each_slice(2).map { |group| Set.new(group) }
  break if (today & yesterday).empty?
end

today & yesterday部分称为&#34;设置相交。&#34;它将返回一个新数组,其中仅包含todayyesterday中相同的组。如果没有组相同(意味着没有重复),则数组将为空。

唯一剩下的就是找出如何保存昨天的小组,以便你可以用它来检查今天的小组。如果您在规定的时间范围内工作(例如,教师为学期创建学生组),那么您可以一次性计算整个学期的学生组。否则,您可能需要将前一天的群组保存到文本文件中,以便日后访问。