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