Javascript - создание всех комбинаций элементов в одном массиве (попарно)

Я видел несколько похожих вопросов о том, как создавать все возможные комбинации элементов в массиве. Но мне очень трудно понять, как написать алгоритм, который будет выводить только пары комбинаций. Любые предложения были бы оценены очень высоко!

Начиная со следующего массива (с N элементами):

var array = ["apple", "banana", "lemon", "mango"];

И получи следующий результат:

var result = [
   "apple banana"
   "apple lemon"
   "apple mango"
   "banana lemon"
   "banana mango"
   "lemon mango"
];

Я пробовал следующий подход, но это приводит ко всем возможным комбинациям, а не только к комбинационным парам.

var letters = splSentences;
var combi = [];
var temp= "";
var letLen = Math.pow(2, letters.length);

for (var i = 0; i < letLen ; i++){
    temp= "";
    for (var j=0;j<letters.length;j++) {
        if ((i & Math.pow(2,j))){ 
            temp += letters[j]+ " "
        }
    }
    if (temp !== "") {
        combi.push(temp);
    }
}

Ответы

Ответ 1

Простым способом было бы сделать двойной цикл для массива, где вы пропускаете первые элементы i во втором цикле.

let array = ["apple", "banana", "lemon", "mango"];
let results = [];

// Since you only want pairs, there no reason
// to iterate over the last element directly
for (let i = 0; i < array.length - 1; i++) {
  // This is where you'll capture that last value
  for (let j = i + 1; j < array.length; j++) {
    results.push('${array[i]} ${array[j]}');
  }
}

console.log(results);

Ответ 2

Вот некоторые решения для функционального программирования:

Использование EcmaScript2019 flatMap:

var array = ["apple", "banana", "lemon", "mango"];

var result = array.flatMap(
    (v, i) => array.slice(i+1).map( w => v + ' ' + w )
);

console.log(result);

Ответ 3

Хотя решения были найдены, я размещаю здесь алгоритм для общего случая, чтобы найти все комбинации размером n из m (m>n) элементов. В вашем случае n=2 и m=4.

const result = [];
result.length = 2; //n=2

function combine(input, len, start) {
  if(len === 0) {
    console.log( result.join(" ") ); //process here the result
    return;
  }
  for (var i = start; i <= input.length - len; i++) {
    result[result.length - len] = input[i];
    combine(input, len-1, i+1 );
  }
}

const array = ["apple", "banana", "lemon", "mango"];    
combine( array, result.length, 0);

Ответ 4

Используя map и flatMap можно сделать следующее (flatMap поддерживается только в Chrome и Firefox)

var array = ["apple", "banana", "lemon", "mango"]
array.flatMap(x => array.map(y => x !== y ? x + ' ' + y : null)).filter(x => x)

Ответ 5

Попробуйте следующее: https://jsfiddle.net/e2dLa9v6/

var array = ["apple", "banana", "lemon", "mango"];
var result = [];

for(var i=0;i<array.length-1;i++){
    for(var j=i+1;j<array.length;j++){
    result.push(array[i]+" "+array[j]);
  }
}
for(var i=0;i<result.length;i++){
    alert(result[i]);
}

Ответ 6

Генерация комбинаций элементов в массиве очень похожа на подсчет в системе счисления, где основание - это количество элементов в вашем массиве (если вы учитываете ведущие нули, которые будут отсутствовать).

Это дает вам все индексы для вашего массива (сцепленные):

arr = ["apple", "banana", "lemon", "mango"]
base = arr.length

idx = [...Array(Math.pow(base, base)).keys()].map(x => x.toString(base))

Вас интересуют только пары из двух, поэтому ограничьте диапазон соответствующим образом:

range = (from, to) = [...Array(to).keys()].map(el => el + from)
indices = range => range.map(x => x.toString(base).padStart(2,"0"))

indices( range( 0, Math.pow(base, 2))) // range starts at 0, single digits are zero-padded.

Теперь осталось сопоставить индексы со значениями.

Поскольку вы не хотите, чтобы элементы были соединены друг с другом, а порядок не имеет значения, их необходимо удалить до сопоставления с конечным результатом.

const range = (from, to) => [...Array(to).keys()].map(el => el + from)
const combinations = arr => {
  const base = arr.length
  return range(0, Math.pow(base, 2))
    .map(x => x.toString(base).padStart(2, "0"))
    .filter(i => !i.match(/(\d)\1/) && i === i.split('').sort().join(''))
    .map(i => arr[i[0]] + " " + arr[i[1]])
}

console.log(combinations(["apple", "banana", "lemon", "mango"]))