Recursive challenge in JS combining all possible array keys in true | false versions, I attach the input and output

自闭症网瘾萝莉.ら 提交于 2020-06-27 16:39:10

问题


I have found many solutions about all posible combinations between array values but I need something different, I hope you could support me. Basically is to create all posible objects that combine array keys with true|false values, something like this:

Input: (Should return an array of 32 objects, 2exp5, two posible values in 5 keys)

let properties = ['arm','lens','season','food','size'];

Output:

let combinations = [
  {"arm": "false","lens": "false","season": "false","food": "false","size": "false"}
  {"arm": "false","lens": "false","season": "false","food": "false","size": "true"}
  {"arm": "false","lens": "false","season": "false","food": "true","size": "true"}
  {"arm": "false","lens": "false","season": "true","food": "true","size": "true"}
  {"arm": "false","lens": "true","season": "true","food": "true","size": "true"}
  {"arm": "true","lens": "true","season": "true","food": "true","size": "true"}
  {"arm": "true","lens": "true","season": "true","food": "false","size": "true"}
  {"arm": "true","lens": "true","season": "false","food": "false","size": "true"}
  and so on...
]

Thank you so much!


回答1:


You could use a 2D matrix with on and off switches for each property. Then create the entries for each key and create the object using Object.fromEntries()

0 0 0 0 0
0 0 0 0 1
0 0 0 1 0
0 0 0 1 1
etc
  • You need a total of 2 ** keys.length objects in the array. So, create that using Array.from({ 2 ** keys.length })

  • In the map function, create a binary number for the current row using row.toString(2)

  • Add the leading 0s until the string is keys.length long: ("00001")

  • split the string to make it an array (["0", "0", "0", "0", "1"])

  • map this array and create an array of entries for the corresponding key

    [["arm","false"],["lens","false"],["season","false"],["food","false"],["size","false"]]

  • Create an object from the array of entries using Object.fromEntries()

Here's a snippet:

let keys = ['arm', 'lens', 'season', 'food', 'size'];

function combination(keys) {
  return Array.from({ length: 2 ** keys.length }, (_, row) =>
    Object.fromEntries(
      row.toString(2)
          .padStart(keys.length, 0)
          .split('')
          .map((binary, j) => [keys[j], String(Boolean(+binary))])
    )
  )
}

console.log(combination(keys))



回答2:


We can build this on two reusable functions, like this:

const crossproduct = (xss) =>
  xss.reduce ((ps, xs) => ps.reduce ((r, p) => [...r, ...(xs.map (x => [...p, x]))], []), [[]])

const mergeAll = xs => 
  Object.assign ({}, ...xs)

const combine = (properties, values) => 
  crossproduct (properties.map (p => values.map (v => ({[p]: v}))))
    .map (mergeAll)


const properties = ['arm', 'lens', 'season', 'food', 'size']
const values = [true, false]

console.log (combine (properties, values))
.as-console-wrapper {min-height: 100% !important; top: 0}

Our utility functions are:

  • crossproduct, which takes an array of arrays and finds the cartesian product of them. For instance,

    crossproduct ([['a', 'b', 'c'], [1, 2], ['x', 'y']])
      //=> [["a", 1, "x"], ["a", 1, "y"], ["a", 2, "x"], ["a", 2, "y"], 
      //    ["b", 1, "x"], ["b", 1, "y"], ["b", 2, "x"], ["b", 2, "y"], 
      //    ["c", 1, "x"], ["c", 1, "y"], ["c", 2, "x"], ["c", 2, "y"]]
    
  • and mergeAll, which combines an array of separate objects into one like this:

    mergeAll ([{foo: 1}, {bar: 2}, {baz: 3}])
      //=> {foo: 1, bar: 2, baz: 3}
    

    This is just a thin wrapper around Object.assign, simply applying it to an array rather than individual objects.

Our main function, combine first creates an array of arrays matching individual property names to values like this:

  [
    [{"arm": true}, {"arm": false}], 
    [{"lens": true}, {"lens": false}], 
    [{"season": true}, {"season": false}], 
    [{"food": true}, {"food": false}], 
    [{"size": true}, {"size": false}]
]

This is the bit properties.map (p => values.map (v => ({[p]: v}))). While that could be extracted as a stand-alone function, it doesn't seem to have any other uses, so the decision is simply a matter of code aesthetics.

We call crossproduct on that result, getting this intermediate format:

[
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": true}, {"size": true}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": true}, {"size": false}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": false}, {"size": true}], 
  [{"arm": true}, {"lens": true}, {"season": true}, {"food": false}, {"size": false}],
  // ... 
  [{"arm": false}, {"lens": false}, {"season": false}, {"food": false}, {"size": false}]
]

And finally, we call .map (mergeAll) on that array to get our final format.

Note that if you really have no other use for mergeAll, it's short and can easily be inlined in the main function as .map (xs => Object.assign ({}, ...xs)). It's a function that I use often and would simply have in handy in my utility toolbox, so I personally wouldn't inline it. You may feel differently.


Do notice the basic idea here. We don't try to solve the problem in one go, but rather apply a series of transforms to get to our final format. This allows us to take advantage of reusable functions for some of those steps. It's a powerful technique.




回答3:


Start building from empty array and add the 2 possibilities for key (true/false). Repeat the process by traversing all keys, for each key take the available results from previous.

let properties = ["arm", "lens", "season", "food", "size"];

const addTwo = (arr, key) => {
  const result = [];
  ["true", "false"].forEach((val) =>
    arr.forEach((item) => result.push({ ...item, [key]: val }))
  );
  return result;
};

const combinations = (arr) => {
  let output = [{}];
  arr.forEach((key) => (output = addTwo(output, key)));
  return output;
};

console.log(combinations(properties));


来源:https://stackoverflow.com/questions/62114826/recursive-challenge-in-js-combining-all-possible-array-keys-in-true-false-vers

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!