生成Javascript对象键/值的排列

时间:2019-07-19 13:42:52

标签: javascript algorithm statistics permutation

我需要创建一个嵌套的选项层次结构。这些选项是具有多个子选项作为嵌套对象的数组上的键。

我需要从该对象生成一个嵌套的层次结构。

从这样的对象开始:

const starterObject = {
    id1: {
        1: { value: "A" },
        2: { value: "B" },
        3: { value: "C" },
    },
    id2: {
        1: { value: 10 },
        2: { value: 20 },
    },
};

我需要以这样的排列对象结束:

const permutations2 = {
    1: [{ value: "A" }, { value: 10 }],
    2: [{ value: "A" }, { value: 20 }],
    3: [{ value: "B" }, { value: 10 }],
    4: [{ value: "B" }, { value: 20 }],
    5: [{ value: "C" }, { value: 10 }],
    6: [{ value: "C" }, { value: 20 }],
};

我尝试过这样的事情:

const starterObject = {
    id1: {
        1: { value: "A" },
        2: { value: "B" },
        3: { value: "C" },
    },
    id2: {
        1: { value: 10 },
        2: { value: 20 },
    },
};


const permutationMatrix = [];

Object.keys(starterObject["id1"]).forEach(key2 =>
  Object.keys(starterObject["id2"]).forEach(key1 =>
    permutationMatrix.push([
      starterObject["id1"][key2],
      starterObject["id2"][key1],
    ])
  )
);

console.log(permutationMatrix)

但是问题是密钥是硬编码的。实际对象将具有1-5个键(id1-id5)和任意数量的嵌套对象。

我认为这需要递归,但是我不确定如何从此处进行。

2 个答案:

答案 0 :(得分:1)

减少,输入和值可以提供帮助,并且无需递归。

const starterObject = {
    id1: {
        1: { value: "A" },
        2: { value: "B" },
        3: { value: "C" },
    },
    id2: {
        1: { value: 10 },
        2: { value: 20 },
    },
    id3: {
        1: { value: 100 }
    }
};

var entries = Object.entries(starterObject)
var out = entries.reduce((arr, group) => {
  const itms = Object.values(group)[1]
  const vals =  Object.values(itms)
  // if first time, set up the initial arrays with first set of data
  if (!arr.length) {
    return vals.map(v => [v])
  }
  // after first one, we will just loop over the arrays
  // and start adding the next set of data to each one
  return arr.reduce((updated, curr) => {
    vals.forEach(val => {
      // make copy so we are not adding data to the reference
      const copy = curr.slice()
      copy.push(val)      
      updated.push(copy)
    })
    return updated
  }, [])
}, [])

console.log(JSON.stringify(out))

答案 1 :(得分:1)

您可以为此使用递归。您的输入/输出格式在某种程度上类似于其数组状对象,键从1开始。因此,我建议使用单独的包装函数,该函数仅负责这种格式转换。

我尝试了一种函数方法,为过程中所需的每个回调创建单独的函数:

const clone = o => ({...o});
const prefixer = item => arr => [item, ...arr].map(clone);
const merger = arr => item => arr.map(prefixer(item));
const extender = group => res => group.flatMap(merger(res));
// The recursive function based on standard array format
const cross = (group, ...rest) => group ? extender(group)(cross(...rest)) : [[]];
// For dealing with the unconventional input/output format: 
const baseOne = (x, i) => [i+1, x];
const generatePermutations = obj =>
    Object.fromEntries(cross(...Object.values(obj).map(Object.values)).map(baseOne));

// Sample data & call
const starterObject = {
    id1: {
        1: { value: "A" },
        2: { value: "B" },
        3: { value: "C" },
    },
    id2: {
        1: { value: 10 },
        2: { value: 20 },
    },
};

const permutations = generatePermutations(starterObject);

console.log(permutations);