web-dev-qa-db-fra.com

Javascript - Générer toutes les combinaisons d'éléments dans un seul tableau (par paires)

J'ai vu plusieurs questions similaires sur la façon de générer toutes les combinaisons possibles d'éléments dans un tableau. Mais j'ai beaucoup de mal à comprendre comment écrire un algorithme qui ne produira que des combinaisons paires . Toutes les suggestions seraient super appréciées!

Commençant par le tableau suivant (avec N éléments): 

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

Et en obtenant le résultat suivant:

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

J'essayais l'approche suivante, mais cela aboutit à toutes les combinaisons possibles, mais uniquement à des paires de combinaisons.

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);
    }
}
6
dhdz

Un moyen simple serait de faire une double boucle for sur le tableau où vous sautez les premiers éléments i de la seconde boucle.

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

// Since you only want pairs, there's 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);

Réécrit avec ES5:

var array = ["Apple", "banana", "lemon", "mango"];
var results = [];

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

console.log(results);

15
Mike Cluck

Voici deux programmation fonctionnelle solutions ES6:

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

var result = array.reduce( (acc, v, i) =>
    acc.concat(array.slice(i+1).map( w => v + ' ' + w )),
[]);

console.log(result);

Ou:

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

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

console.log(result);

12
trincot

Bien que des solutions aient été trouvées, je publie ici un algorithme permettant de trouver toutes les combinaisons taille n de m (m>n) éléments. Dans votre cas, nous avons n=2 et 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);

8
nhnghia

Générer des combinaisons d'éléments dans un tableau ressemble beaucoup à compter dans un système numérique, Où la base correspond au nombre d'éléments de votre tableau (si vous tenez compte des zéros qui seront manquants).

Cela vous donne tous les indices de votre tableau (concaténés):

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

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

Vous n'êtes intéressé que par paires de deux, alors restreignez la plage en conséquence:

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.

Reste maintenant à mapper les index sur les valeurs.

Comme vous ne voulez pas que les éléments soient associés à eux-mêmes et que l'ordre n'ait pas d'importance, il faut supprimer ceux-ci avant de les mapper au résultat final.

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

Avec plus de dix éléments, toString() renverra des lettres pour les index; De plus, cela ne fonctionnera qu'avec 36 éléments maximum.

0
Kolja

Essayez ceci: 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]);
}
0
Konstantinos

map et flatMap permettent d'effectuer les opérations suivantes (flatMap est uniquement pris en charge sur chrome et firefox

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