2016-02-28 41 views
0

如何獲得數組中2個元素的每種可能組合?獲取元素的所有可能組合

例如:

[ 
    1, 
    2, 
    3, 
    4 
] 

becomes 

[ 
    [1, 2], 
    [1, 3], 
    [1, 4], 
    [2, 1], 
    [2, 3], 
    [2, 4], 
    [3, 1], 
    [3, 2], 
    [3, 4], 
    [4, 1], 
    [4, 2], 
    [4, 3] 
] 

這個答案使用蠻力,但有沒有用Ramda和或鑽營的功能呢?

var arr = [1, 2, 3, 4], 
    result = []; 
for(var i=0; i<arr.length; ++i) 
    for(var j=0; j<arr.length; ++j) 
    if(i !== j) 
     result.push([arr[i], arr[j]]); 

回答

2

這裏是一個優雅的解決方案:

// permutations :: Number -> [a] -> [[a]] 
const permutations = R.compose(R.sequence(R.of), R.flip(R.repeat)); 

使用示例:

permutations(2, [1, 2, 3, 4]); 
// => [[1, 1], [1, 2], ..., [4, 3], [4, 4]] 

permutations(3, [1, 2, 3, 4]); 
// => [[1, 1, 1], [1, 1, 2], ..., [4, 4, 3], [4, 4, 4]] 
+2

它很優雅,但它返回與請求不同的東西,因爲它重複了這些元素。從列表中得出的n元素序列,它和我所看到的一樣優雅 –

+0

你是對的,斯科特這個答案是錯誤的,但是很有趣:) – davidchambers

+0

這個過濾器可以移除任何東西重複 – sa555

1

你不需要任何庫,你可以在平凡香草JS使用嵌套循環做

var as = [1, 2, 3, 4] 

var f = xs => 
    R.pipe(
     R.chain(a => R.map(b => a == b ? [] : [a, b])(xs)) 
    , R.filter(R.pipe(R.isEmpty, R.not)) 
)(xs) 

console.log(f(as)) 

PS。爲LiveScript有這個好的句法: http://homam.github.io/try-livescript/#welcome/lists

爲了選擇螞蟻大小的一個子集:Ramda code

var g = (xs, n) => 
    n == 0 ? [[]] : 
    R.isEmpty(xs) ? [] : 
     R.concat(
      R.map(R.prepend(R.head(xs)), g(R.tail(xs), n - 1)) 
     , g(R.tail(xs), n) 
    ) 

g(as, 3) 
+0

但是,這是否直接地擴展到任何大小的分組? –

+0

@ScottSauyet不,但問題是關於2個組合,而不是n個組合。 – Oriol

+0

你說得對。我想是在對OP的另一個答案進行後續評論時,OP說明了目標可能更一般。如果目標僅僅是2-combinators,你顯然是最好的答案。 –

3

借用哈斯克爾:

as = [1, 2, 3] 

f xs = do 
    a <- xs 
    b <- xs 
    return $ if a == b then [] else [a, b] 

main = print $ filter (not . null) . f $ as 

這是my Ramda versionDerive every possible combination of elements in array

+1

您也可以通過使用'chain'而不是'map'來跳過顯式過濾器(並且在haskell示例中放入'return') '鏈(a =>鏈(b => a == b?[]:[[a,b]],xs),xs)' –

+0

這個更新的版本可能比OP詢問更有趣的問題,比如說,來自一組四個不同元素的所有2元素組合。但區分'[1,2]'和'[2,1]'的問題,這是不行的。 –

0

這將爲置換的任何長度的工作只是進行調整,在2

切斷

function permutate(input, output) { 
 
    if (input.length === 0) { 
 
    document.body.innerHTML += "<div>" + output + "</div>"; 
 
    } 
 

 
    for (var i = 0; i < input.length; i++) { 
 
    output.push(input[i]); 
 
    permutate(input.slice(0, i).concat(input.slice(i + 1)), output); 
 
    output.pop(); 
 
    } 
 
} 
 

 
permutate([1, 2, 3, 4], []);

+0

你是什麼意思,「調整它切斷2?「 –

+0

將它調整爲不會繼續超過2次遞歸的深度 – highstakes

0

如果你只是想要兩個EL來自Oriol的answer應該會很好。但是,如果你想要的東西,擴展到任何大小分組,這樣的事情可能會做:

const permutations = (n, tokens, subperms = [[]]) => 
    n < 1 || n > tokens.length ? 
    subperms  : 
    R.addIndex(R.chain)((token, idx) => permutations(
     n - 1, 
     R.remove(idx, 1, tokens), 
     R.compose(R.map, R.append)(token)(subperms) 
    ), tokens); 


permutations(2, [1, 2, 3, 4]); 
//=> [[1, 2], [1, 3], [1, 4], [2, 1], [2, 3], [2, 4], 
// [3, 1], [3, 2], [3, 4], [4, 1], [4, 2], [4, 3]] 

permutations(3, [1, 2, 3, 4]); 
//=> [[1, 2, 3], [1, 2, 4], [1, 3, 2], [1, 3, 4], [1, 4, 2], [1, 4, 3], 
// [2, 1, 3], [2, 1, 4], [2, 3, 1], [2, 3, 4], [2, 4, 1], [2, 4, 3], 
// [3, 1, 2], [3, 1, 4], [3, 2, 1], [3, 2, 4], [3, 4, 1], [3, 4, 2], 
// [4, 1, 2], [4, 1, 3], [4, 2, 1], [4, 2, 3], [4, 3, 1], [4, 3, 2]] 

這個版本稍微改編自Ramda's Gitter room一個I presented。在那裏我建議它是過度的,但那是完全排列的。這似乎適用於n組合。

你可以看到它在Ramda REPL行動。

+0

@davidchambers:感謝您的編輯工作太快! –