2012-03-26 6 views
2

この問題はC#や他の言語では解決されていますが、Smalltalkでは解決されていません。私は3つのコレクションを持っています:例えば、Smalltalkのコレクションからすべての組み合わせを生成する

a := #(3 4 5). 
b := #(4 1 2). 
c := #(5 2 3). 

と私はすべての可能な組み合わせを作る必要があります。 atATimeDo:E:

#(3 4 5) 
#(3 4 2) 
#(3 4 3) 

#(3 1 5) 
#(3 1 2) 
#(3 1 3) 

#(3 2 5) 
#(3 2 2) 
#(3 2 3) 

#(4 4 5) 
... 

私はSqueakのとファロで見てきたが組み合わせがあるが、私はこのような場合のためにそれを使用する方法を得ることはありません。これは宿題ではありません。どんな助け?

答えて

2

ここは、Smalltalk/Xのクラスライブラリ(SequentialCollection内)のコードです。 最後の使用例コメントを参照してください。


combinationsDo: aBlock 
    "Repeatly evaluate aBlock with all combinations of elements from the receivers elements. 
    The receivers elements must be collections of the individuals to be taken for the combinations" 

    self combinationsStartingAt:1 prefix:#() do:aBlock 

combinationsStartingAt:anInteger prefix:prefix do:aBlock 
    "a helper for combinationsDo:" 

    |loopedElement| 

    loopedElement := self at:anInteger. 

    anInteger == self size ifTrue:[ 
     loopedElement do:[:el | aBlock value:(prefix copyWith:el)]. 
     ^self. 
    ]. 

    loopedElement do:[:el | 
     |newPrefix| 

     newPrefix := (prefix copyWith:el). 
     self combinationsStartingAt:anInteger+1 prefix:newPrefix do:aBlock 
    ]. 

    " 
    (Array 
      with:($a to:$d) 
      with:(1 to: 4)) 
     combinationsDo:[:eachCombination | Transcript showCR: eachCombination] 
    " 
    " 
    (Array 
      with:#(1 2 3 4 5 6 7 8 9) 
      with:#(A)) 
     combinationsDo:[:eachCombination | Transcript showCR: eachCombination] 
    " 
    " 
    #((3 4 5) 
     (4 1 2) 
     (5 2 3) 
    ) combinationsDo:[:eachCombination | Transcript showCR: eachCombination] 
    " 
3

これはビット不可解が、短いです。このブロックは無名関数として使用されます(並べ替え、再帰的に呼び出すことができるように変数から参照する必要があります)。

| expand | 
expand := [ :prefix :lists | 
    lists isEmpty 
     ifTrue: [ Array with: prefix ] 
     ifFalse: [ | tail | 
      tail := lists allButFirst: 1. 
      lists first inject: #() into: [ :all :each | 
       all, (expand value: (prefix copyWith: each) value: tail) ] ] ]. 
expand value: #() value: #((3 4 5)(4 1 2)(5 2 3)) 
1

組み合わせの目的:atATimeDo:指定されたサイズのパーティションを計算することです。
デカルト積を得るには、Martin Kobeticが提供する再帰関数バージョンが最短のコードです。
ここに反復型があります:

| arrayOfArray n p cartesianProduct | 
arrayOfArray := #(
    #(3 4 5) 
    #(4 1 2) 
    #(5 2 3) 
). 
n := arrayOfArray size. 
p := arrayOfArray inject: 1 into: [:product :array | product * array size]. 
cartesianProduct := (Array new: p) collect: [:i | Array new: n]. 
1 to: p do: 
    [:iSol | 
    | packetIndex | 
    packetIndex := iSol - 1. 
    n to: 1 by: -1 do: 
     [:iVar | 
     | ni valuesOfIVar | 
     ni := (valuesOfIVar := arrayOfArray at: iVar) size. 
     (cartesianProduct at: iSol) 
      at: iVar put: (valuesOfIVar at: packetIndex \\ ni + 1). 
     packetIndex := packetIndex // ni]]. 
^cartesianProduct