2016-02-28 3 views
0

Как бы вы получили всевозможные комбинации из двух элементов в массиве?Получите все возможные комбинации элементов

Например:

[ 
    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 и или выделки? Derive every possible combination of elements in array

ответ

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-element последовательностей, взятых из списка. И это так же изящно, как я видел. –

+0

Вы правы, Скотт. Этот ответ неверен, но интересен тем не менее. :) – davidchambers

+0

Это работает с фильтром для удаления любых дубликаты – sa555

1

Вам не нужна библиотека, вы можете сделать это тривиально в ванильно-JS с помощью вложенного цикла:

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]]); 
+0

Но разве это распространяется прямолинейно любых размеров подгрупп? –

+0

@ScottSauyet Нет, но вопрос о 2-объединениях, а не n-комбинациях. – Oriol

+0

Вы правы. Я предполагаю, что в последующем комментарии к другому ответу, что ОП дал понять, что цель, вероятно, более общая. Ваш, безусловно, лучший ответ, если цель - просто 2-комбинаторы. –

3

заимствование из Haskell:

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 version:

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) 
+1

Вы также можете пропустить явный фильтр, используя 'chain' вместо' map' (и отбрасывая 'return' в примере haskell), например. 'chain (a => chain (b => a == b? []: [[a, b]], xs), xs)' –

+0

Эта обновленная версия отвечает, пожалуй, более интересный вопрос, чем запрос ФП, скажем, все 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

Если вы просто хотите, два эл answer от Oriol должно все хорошо. Но если вы хотите что-то, что простирается до любого размера подгруппы, что-то подобное может сделать:

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]] 

Эта версия была слегка адаптирована из одного I presented в Ramda's Gitter room. Там я предположил, что это было перегружено, но это было для полных перестановок. Кажется уместным n-комбинации.

Вы можете увидеть это в действии на Ramda REPL.

+0

@ davidchambers: Спасибо за редактирование. Работа слишком быстро! –

Смежные вопросы