查找JS中2个数组的所有排列

时间:2019-05-22 08:44:43

标签: javascript algorithm

我正在尝试查找2个数组的每个排列,如下所示:

// input
lowerWords = ['one', 'two', 'three' ] 
upperWords = [ 'ONE', 'TWO', 'THREE' ]

// output
keywords = {
  'one two three': true,
  'ONE two three': true,
  'ONE TWO three': true,
  'ONE TWO THREE': true,
  'ONE two THREE': true,
  'one TWO three': true,
  'one two THREE': true,
  'one TWO THREE': true,
}

它应该与3个以上的项目一起工作,两个数组的长度始终相同。这是我的代码:

const keywords = {}
const lowerWords = ['one', 'two', 'three' ] 
const upperWords = [ 'ONE', 'TWO', 'THREE' ]
const wordCount = lowerWords.length

let currentWord = 0
let currentWords = [...upperWords]
while (currentWord < wordCount) {
  currentWords[currentWord] = lowerWords[currentWord]
  let keyword = currentWords.join(' ')
  keywords[keyword] = true
  currentWord++
}

currentWord = 0
currentWords = [...lowerWords]
while (currentWord < wordCount) {
  currentWords[currentWord] = upperWords[currentWord]
  let keyword = currentWords.join(' ')
  keywords[keyword] = true
  currentWord++
}

结果缺少一些

ONE TWO THREE: true
ONE TWO three: true
ONE two three: true
one TWO THREE: true
one two THREE: true
one two three: true

6 个答案:

答案 0 :(得分:9)

您可以转置数组以获取对数组,然后获取对的所有组合。

const
    transpose = array => array.reduce((r, a) => a.map((v, i) => [...(r[i] || []), v]), []),
    combinations = array => array.reduce((a, b) => a.reduce((r, v) => r.concat(b.map(w => [].concat(v, w))), []));

var lowerWords = ['one', 'two', 'three'],
    upperWords = ['ONE', 'TWO', 'THREE'],
    pairs = transpose([lowerWords, upperWords]),
    result = combinations(pairs);
    
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 1 :(得分:1)

我想尝试一下。我使用二进制文件来获得可能的组合,因为此问题需要以2为基础的解决方案:

const low = ["one", "two", "three"];
const up = ["ONE", "TWO", "THREE"];

const words = [low, up]
const len = words[0].length


function getCombinations(noOfArrays, len) {
  var temp, newCombo, combos = [];
  for (var i = 0; i < (noOfArrays ** len); i++) {
    temp = new Array(len).fill(0)
    newCombo = i.toString(noOfArrays).split('');
    newCombo.forEach((el, i) => temp[temp.length - newCombo.length + i] = +el);
    combos.push(temp);
  }
  return combos;
}

function setCombinations(combos) {
  return combos.map(combo => combo.map((el, i) => words[el][i]))
}


var combos = getCombinations(words.length, len)
combos = setCombinations(combos)


console.log(combos)

循环说明:

1. temp = new Array(len).fill(0)
2. newCombo = i.toString(2).split("");
3. newCombo.forEach((el, i) => temp[temp.length - newCombo.length + i] = +el);
  1. 创建临时数组[0,0,0]
  2. 获取循环号(i)并将其转换为二进制,例如:
1 -> 1
2 -> 10
3 -> 11
4 -> 100
etc...

然后将二进制文件拆分为数组100 -> [1,0,0]

  1. 然后为每个元素将其推送到新数组中。这给将1和2元素数组(10 -> [1,0])推入数组的后面带来了问题。我用temp.length - newCombo.length + i来解决这个问题。

然后该函数返回:

[ 0, 0, 0 ]
[ 0, 0, 1 ]
[ 0, 1, 0 ]
[ 0, 1, 1 ]
[ 1, 0, 0 ]
[ 1, 0, 1 ]
[ 1, 1, 0 ]
[ 1, 1, 1 ]

然后,我可以映射每个组合,并根据值获取每个数组,并通过循环索引获取单词(“ one”或“ ONE”)。

  

请注意,此代码可用于多个数组,只要数组的长度都相同。

答案 2 :(得分:1)

我们可以直接列举这些。这可能是您了解递归的好机会。该算法非常简单:

If we've reached the end of
the list, return the combination
the current recursion branch is
building.

Otherwise, create a new branch
that picks the next item from B,
while the current branch picks
the next item from A.

JavaScript代码:

function f(A, B, i=0, comb=[]){
  return i == A.length
         ? [comb]
         : f(A, B, i + 1, comb.concat(A[i])).concat(
           f(A, B, i + 1, comb.slice().concat(B[i])))
}

console.log(JSON.stringify(f(['one','two','three'], ['ONE','TWO','THREE'])))

答案 3 :(得分:1)

您总共需要获得2 ^ 3个组合。如果您从2个数组中创建2D矩阵,则下表代表应从中获取该项的行号。

0 0 0
0 0 1
0 1 0
0 1 1
1 0 0
1 0 1
1 1 0
1 1 1

如果分析组合的索引,则每个组合都是从0到2 ^ 3的二进制数,前导零。

所以,您可以

  • 从0循环到8
  • 使用toString(2)
  • 创建二进制数
  • 使用padStart
  • 添加前导零
  • split每个数字获取一个数组
  • matrix[digit-from-binary][position-of-each-split]
  • 获取每个项目
  • join带有' '分隔符的项目数组,以获取 key
  • 将密钥添加到输出对象

function getAllCombinations(matrix) {
  const combinations = 2 ** 3,
        output = {};
  
  for(let i = 0; i < combinations; i++) {
      const key = i.toString(2)
                    .padStart(3, 0)
                    .split('')
                    .map((n, j) => matrix[n][j])
                    .join(" ")
                    
      output[key] = true;
  }
  
  return output
}

console.log(getAllCombinations([['one', 'two', 'three' ],[ 'ONE', 'TWO', 'THREE' ]]))

您可以将其概括为m x n矩阵。您无需将其分别转换为二进制数,而需要将其转换为base-m并将padStart转换为长度n

function getAllCombinations(matrix) {
  const rows = matrix.length,
        columns = matrix[0].length,
        combinations = rows ** columns,
        output = {}
  
  for(let i = 0; i < combinations; i++) {
      const key = i.toString(rows)
                    .padStart(columns, 0)
                    .split('')
                    .map((n, j) => matrix[n][j])
                    .join(" ")
                    
      output[key] = true;
  }
  
  return output
}

console.log(getAllCombinations([[1, 2, 3 ],[ 4, 5, 6], [ 7, 8, 9]])) // 3 x 3 matrix
console.log(getAllCombinations([[1, 2], [3, 4], [5, 6], [7, 8]])) // 4 x 2 matrix
.as-console-wrapper { max-height: 100% !important; top: 0; }

答案 4 :(得分:0)

以下代码应为您提供递归方法:

const sidebarOpen = 'SIDEBAR_OPEN';
const initialState = { show: false }

export const actionCreators = {
    open: () => ({
        type: sidebarOpen
    })    
};

export const reducer = (state, action) => {
    state = state || initialState;
    console.log("Initial State");
    console.log(state)
    if (action.type === sidebarOpen) {
        return {
            ...state,
            show: state.show = true
        };
    } else {
        return {            
            ...state,
            show: state.show = false
        }
    }    
    return state;
};

答案 5 :(得分:0)

这是基于我的其他answer的通用版本,该版本处理可变长度的可变数量的输入数组:

const g = (arrs, i=0, comb=[]) =>
  !arrs.some(arr => i < arr.length)
  ? [comb]
  : arrs.reduce((acc, arr) => 
      i >= arr.length ? acc :
      acc.concat(g(arrs, i + 1, comb.slice().concat(arr[i])))
    , [])
    

// Example output
let input = [['ONE','TWO','THREE'], ['one','two'], [1,2,3,4]]

let str = ''
for (let line of g(input))
  str += JSON.stringify(line) + '\n'
console.log(str)