2016-02-28 45 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:感谢您的编辑工作太快! –