プレゼント交換のペアを決めるスクリプト


#二組四人のときに四通り…というくだりで気づくべきでした(^_^;)。当方で問題を取り違えておりました。ごめんなさい。以下はそのまま晒しておきますが、タイトル共に間違いでリンク先の“お題”とは全然関係ない内容になってしまっていますので、どうぞあしからず。 id:sumim:20061221:p1 でやり直しました。


鍋あり谷あり - あなたならどうお書きになります1.0 にチャレンジ。まずは SqueakSmalltalk で。

| flattenAll groups pairs |

groups := #((a1 a2 a3) (b1 b2 b3) (c1 c2) (d1 d2)).                 " グループ分けされた参加者たち "
groups := groups collect: [:group | group asOrderedCollection].     " 各グループを配列からコレクションに "
groups := groups asSortedCollection: [:g1 :g2 | g1 size > g2 size]. " グループ群をソート済みコレクションに "

pairs := OrderedCollection new.                                     " 結果出力用コレクション準備 "

flattenAll := [:gps |                                               " Smalltalk にない flatten を定義 "
   Array streamContents: [:ss | gps do: [:gp | ss nextPutAll: gp]]].

[groups notEmpty] whileTrue: [                                      " グループ群が空でない間、繰り返し "
   | largestGroup selectedPerson anotherPerson |
   largestGroup := groups reSort removeFirst.                       " 最も人数の多いグループを抽出 "
   selectedPerson := largestGroup removeFirst.                      " 最多人数グループから一人を抽出 "
   anotherPerson := (flattenAll value: groups) atRandom.            " 残りのグループ群から任意の交換相手を選ぶ "
   groups do: [:group | group remove: anotherPerson ifAbsent: []].  " 残りのグループ群から交換相手を探して外す "
   groups add: largestGroup.                                        " グループ群に最多人数グループを戻す "
   groups := groups reject: [:group | group isEmpty].               " グループ群から空のグループを排除 "
   pairs add: {selectedPerson. anotherPerson} copy sort].           " 抽出したペアを結果に追加 "

^ pairs asArray                                                     " 結果の出力 "
=> #((b1 d2) (a1 c2) (a2 b2) (a3 c1) (b3 d1))


これを Ruby へ直訳ぎみに変換。(shuffle を使っているので、要 1.9)(←変えました)

groups = [["a1","a2","a3"],["b1","b2","b3"],["c1","c2"],["d1","d2"]]

pairs = []

class Array
  def at_random; self[rand(size)] end
  def remove_first; shift end
end

until (groups.empty?) do
  largestGroup = (groups.sort!{ | g1, g2 | g2.size <=> g1.size }).remove_first
  selectedPerson = largestGroup.remove_first
  anotherPerson = groups.flatten.at_random
  groups.each{ | group | group.delete(anotherPerson) }
  groups << largestGroup
  groups.reject!{ | group | group.empty? }
  pairs << [selectedPerson, anotherPerson].sort
end

p pairs
=> [["a1", "b2"], ["b1", "c1"], ["a2", "c2"], ["b3", "d1"], ["a3", "d2"]]