Javascript - Generating all combinations of elements in a single array (in pairs)

后端 未结 9 617
天命终不由人
天命终不由人 2020-11-28 11:14

I\'ve seen several similar questions about how to generate all possible combinations of elements in an array. But I\'m having a very hard time figuring out how to write an a

相关标签:
9条回答
  • 2020-11-28 11:50

    Generating combinations of elements in an array is a lot like counting in a numeral system, where the base is the number of elements in your array (if you account for the leading zeros that will be missing).

    This gives you all the indices to your array (concatenated):

    arr = ["apple", "banana", "lemon", "mango"]
    base = arr.length
    
    idx = [...Array(Math.pow(base, base)).keys()].map(x => x.toString(base))
    

    You are only interested in pairs of two, so restrict the range accordingly:

    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.
    

    Now what's left to do is map indices to values.

    As you don't want elements paired with themselves and order doesn't matter, those need to be removed, before mapping to the final result.

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

    With more than ten elements, toString() will return letters for indices; also, this will only work with up to 36 Elements.

    0 讨论(0)
  • 2020-11-28 11:53

    I ended up writing a general solution to this problem, which is functionally equivalent to nhnghia's answer, but I'm sharing it here as I think it's easier to read/follow and is also full of comments describing the algorithm.

    
    /**
     * Generate all combinations of an array.
     * @param {Array} sourceArray - Array of input elements.
     * @param {number} comboLength - Desired length of combinations.
     * @return {Array} Array of combination arrays.
     */
    function generateCombinations(sourceArray, comboLength) {
      const sourceLength = sourceArray.length;
      if (comboLength > sourceLength) return [];
    
      const combos = []; // Stores valid combinations as they are generated.
    
      // Accepts a partial combination, an index into sourceArray, 
      // and the number of elements required to be added to create a full-length combination.
      // Called recursively to build combinations, adding subsequent elements at each call depth.
      const makeNextCombos = (workingCombo, currentIndex, remainingCount) => {
        const oneAwayFromComboLength = remainingCount == 1;
    
        // For each element that remaines to be added to the working combination.
        for (let sourceIndex = currentIndex; sourceIndex < sourceLength; sourceIndex++) {
          // Get next (possibly partial) combination.
          const next = [ ...workingCombo, sourceArray[sourceIndex] ];
    
          if (oneAwayFromComboLength) {
            // Combo of right length found, save it.
            combos.push(next);
          }
          else {
            // Otherwise go deeper to add more elements to the current partial combination.
            makeNextCombos(next, sourceIndex + 1, remainingCount - 1);
          }
            }
      }
    
      makeNextCombos([], 0, comboLength);
      return combos;
    }
    
    
    0 讨论(0)
  • 2020-11-28 11:54

    Just to give an option for next who'll search it

    const arr = ['a', 'b', 'c']
    const combinations = ([head, ...tail]) => tail.length > 0 ? [...tail.map(tailValue => [head, tailValue]), ...combinations(tail)] : []
    console.log(combinations(arr)) //[ [ 'a', 'b' ], [ 'a', 'c' ], [ 'b', 'c' ] ]

    0 讨论(0)
提交回复
热议问题