如何从对象数组中的嵌套数组中获取数组值的组合

5

我是一位有用的助手,可以为您进行文本翻译。以下是需要翻译的内容:

我有一个对象数组,其结构如下:

 var varientSections = [
  {
    type: "frame",
    values: ["black", "white", "wood"]
  },
  {
    type: "finish",
    values: ["matte", "glossy"]
  }
];

我希望能够获取数组值的组合,并使用它创建新列表。目前,我可以通过名为getCombination(varientSections)的方法从嵌套的数组值中检索组合。但是,我不知道如何创建具有以下结构的新列表:

var results = [
  {
    attributes: [
      {
        type: "frame",
        value: "black"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "black"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "white"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "white"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "wood"
      },
      {
        type: "finish",
        value: "matte"
      }
    ]
  },
  {
    attributes: [
      {
        type: "frame",
        value: "wood"
      },
      {
        type: "finish",
        value: "glossy"
      }
    ]
  }
];

以下是我的代码:
function getCombinations(arr) {
  if (arr.length === 0) {
    return [[]];
  }

  let [current, ...rest] = arr;
  let combinations = getCombinations(rest);

  var result = current.values.reduce(
    (accumulator, currentValue) => [
      ...accumulator,
      ...combinations.map(c => [currentValue, ...c])
    ],
    []
  );
  console.log("result is ");
  console.log(result);
  return result;
}

let varientCombinations = getCombinations(varientSections);
console.log(varientCombinations);

let updatedVarientDetails = [];
varientSections.forEach((varientSection, index) => {
  let type = varientSection.type;
  varientCombinations.forEach(combination => {
    let obj = [
      {
        type: type,
        value: combination[index]
      },
    ];
    updatedVarientDetails.push(obj);
  });
});

console.log(updatedVarientDetails);

你能否只使用JavaScript的concat方法呢? - Maiken Madsen
嗨@MaikenMadsen,谢谢回复。你是什么意思?我对任何方法都开放!我只想按照我上面提到的结构生成列表。 - Issaki
这是来自w3school的一个简单示例:https://www.w3schools.com/jsref/jsref_concat_array.asp - Maiken Madsen
2个回答

6
你可以得到笛卡尔积,稍后再为其添加所需的样式。名称和值是从传递的对象中获取的。
该算法获取所有键/值对,并严格查看值,也就是说,如果找到数组或对象,即w && typeof w === "object",则会使用实际部分来添加其他键/值对。
例如,一个具有两个属性的小对象。
{ a: 1, b: [2, 3] }

产出
[    { a: 1, b: 2 },    { a: 1, b: 3 }]

更加高级的对象,例如

{ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }

产生的结果与给定的结构相同。
[
    {
        a: 1,
        b: {
            c: { d: 2, e: 4 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 2, e: 5 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 3, e: 4 }
        }
    },
    {
        a: 1,
        b: {
            c: { d: 3, e: 5 }
        }
    }
]

那意味着,从任何找到的子对象中取得笛卡尔积并与实际值结合。

const
    getCartesian = object => Object.entries(object).reduce(
        (r, [key, value]) => {
            let temp = [];
            r.forEach(s =>
                (Array.isArray(value) ? value : [value]).forEach(w =>
                    (w && typeof w === "object" ? getCartesian(w) : [w]).forEach(x =>
                        temp.push({ ...s, [key]: x })
                    )
                )
            );
            return temp;
        },
        [{}]
    ),
    data = [{ type: "frame", value: ["black", "white", "wood"] }, { type: "finish", value: ["matte", "glossy"] }],
    result = getCartesian(data)
        .map(o => ({ attributes: Object.assign([], o).map(({ ...o }) => o) }));

console.log(result);

console.log(getCartesian({ a: 1, b: { c: { d: [2, 3], e: [4, 5] } } }));
.as-console-wrapper { max-height: 100% !important; top: 0; }


你是否可以为我写一些注释,以便我理解? - Issaki

3
你可以简化为这样:

var variantSections = [
  {
    type: "frame",
    values: ["black", "white", "wood"]
  },
  {
    type: "finish",
    values: ["matte", "glossy"]
  }
];

// iterate through each variantSection and create objects like {"type": "frame", "value": "black"}
var sections = variantSections.map(variant => {
 return variant.values.map(val => ({type: variant.type, value: val}))
});

// then iterate through the two resulting arrays of objects, combining each into the attributes object you want
var results = [];
for (var i = 0; i < sections[0].length; i++) {
 for (var j = 0; j < sections[1].length; j++) {
  results.push({attributes: [sections[0][i], sections[1][j]]});
 }
}

console.log(JSON.parse(JSON.stringify(results)));


嗨,@Nick G,感谢您的回复!我非常感激。但是,Nina Scholz在您之前回答了几分钟。因此,我接受了他的答案。再次感谢! - Issaki

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接