从Smalltalk中的集合生成所有组合

时间:2012-03-26 07:01:20

标签: combinations smalltalk squeak pharo

我已经看到这个问题已经解决了C#和其他语言,但不适用于Smalltalk。我有3个集合,例如:

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

我需要做出所有可能的组合,我。 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和Pharo中看到有组合:atATimeDo:但我不知道如何在这种情况下使用它。这不是功课。有什么帮助吗?

3 个答案:

答案 0 :(得分: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 :(得分: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]
    "

答案 2 :(得分: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