首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >如何将Javascript中的元素分组以获得javascript中的笛卡儿产品

如何将Javascript中的元素分组以获得javascript中的笛卡儿产品
EN

Stack Overflow用户
提问于 2022-09-24 05:32:37
回答 2查看 53关注 0票数 1

我有一个场景,我有一个像这样的对象。

代码语言:javascript
运行
复制
   [
    {attributeGroupId:2, attributeId: 11, name: 'Diamond'}
    {attributeGroupId:1, attributeId: 9, name: '916'}
    {attributeGroupId:1, attributeId: 1, name: '24K'}
    {attributeGroupId:2, attributeId: 12, name: 'Square'}
]

预期结果:

代码语言:javascript
运行
复制
[
    {attributeGroupId:2, attributeId: 11, name: 'Diamond'},
    {attributeGroupId:2, attributeId: 12, name: 'Square'}
]

代码语言:javascript
运行
复制
[
    {attributeGroupId:1, attributeId: 9, name: '916'},
    {attributeGroupId:1, attributeId: 1, name: '24K'}
]

所以我可以像这样制作笛卡儿的乘积,

代码语言:javascript
运行
复制
[
     {attributeId: 11-9, name: 'Diamond-916'}, 
     {attributeId: 11-1, name: 'Diamond-24K'},
     {attributeId: 12-9, name: 'Square-916'}, 
     {attributeId: 12-1, name: 'Square-24K'},
]

现在,我希望保持这个逻辑尽可能通用,因为运行时不知道attributeGroupId的数量。

我认为根据attributeGroupId将数组拆分为多个较小的数组应该是第一步。

EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2022-09-24 06:13:22

您可以实现这样的基本过滤器函数:

代码语言:javascript
运行
复制
function filterForAttributeGroupId(data, id) {
  return data.filter((item) => item.attributeGroupId === id);
}

console.log(filterForAttributeGroupId(data, 1)) //contains all elements with attributeGroupId = 1
console.log(filterForAttributeGroupId(data, 2)) //contains all elements with attributeGroupId = 2

这里有一个通用解决方案,返回一个过滤数组数组:

代码语言:javascript
运行
复制
function filterForAttributeGroupId(data) {
  const mem = {};
  data.forEach((item) => {
    if ( mem[item.attributeGroupId] ) {
      mem[item.attributeGroupId].push(item);
    } else {
      mem[item.attributeGroupId] = [item];
    }
  })
  return Object.values(mem);
}

编辑在注释反馈后,如果连接属性的顺序无关紧要,可以使用以下代码获得n个不同数组的“笛卡儿级联”:

代码语言:javascript
运行
复制
function cartesianProduct(arrays) {
  if (arrays.length <= 1 ) return arrays[0];
  const first = arrays[0];
  const second = cartesianProduct(arrays.slice(1));
  const result =  [];
   first.forEach(( itemFirst ) => {
      second.forEach( (itemSecond) => {
        result.push({attributeId: `${itemFirst.attributeId}-${itemSecond.attributeId}`, name: `${itemFirst.name}-${itemSecond.name}`})
      });
   });
   return result;
}

通过这种方式调用以下内容:

代码语言:javascript
运行
复制
console.log(cartesianProduct(filterForAttributeGroupId(data)));

在预期数据中的结果(尽管字符串按另一个顺序连接):

代码语言:javascript
运行
复制
[
  {
    "attributeId":"9-11",
    "name":"916-Diamond"
  },
  {
    "attributeId":"9-12",
    "name":"916-Square"
  },
  {
    "attributeId":"1-11",
    "name":"24K-Diamond"
  },
  {
    "attributeId":"1-12",
    "name":"24K-Square"
  }
]
票数 1
EN

Stack Overflow用户

发布于 2022-09-26 16:31:45

我认为最好把这个逻辑分解成几块。首先,数组的笛卡儿乘积函数似乎非常有用。因此,让我们为它建立一个实用函数。其次,基于某些共享特性将数组分解为子数组也很常见。所以让我们再做一个。

然后,我们可以编写一个简单的主函数,该函数按attributeGroupId对id进行分组,并对其调用笛卡尔积,然后对结果数组中的每个项调用如下

代码语言:javascript
运行
复制
[
  {attributeGroupId: 2, attributeId: 11, name: "Diamond"},
  {attributeGroupId: 1, attributeId: 9, name: "916"}
]

我们可以通过组合attributeIdname属性来创建一个新对象。

代码语言:javascript
运行
复制
const cartesian = ([xs, ...xss]) =>
  xs == undefined ? [[]] : xs .flatMap (x => cartesian (xss) .map (ys => [x, ...ys]))

const group = (fn, k) => (xs) => Object .values (xs .reduce (
  (a, x) => ((k = 'x' + fn (x)), (a [k] = a [k] || []), (a [k] .push (x)), a), {}
))

const regroupAtts = (xs) => 
  cartesian (group (x => x .attributeGroupId) (xs))
    .map (xs => ({
      attributeId: xs .map (x => x .attributeId) .join ('-'),
      name: xs .map (x => x.name) .join ('-')
    }))

const atts = [{attributeGroupId: 2, attributeId: 11, name: 'Diamond'}, {attributeGroupId: 1, attributeId: 9, name: '916'}, {attributeGroupId: 1, attributeId: 1, name: '24K'}, {attributeGroupId: 2, attributeId: 12, name: 'Square'}]
const atts2 = [{attributeGroupId: 2, attributeId: 11, name: 'Diamond'}, {attributeGroupId: 1, attributeId: 9, name: '916'}, {attributeGroupId: 3, attributeId: 101, name: 'foo'}, {attributeGroupId: 1, attributeId: 1, name: '24K'}, {attributeGroupId: 3, attributeId: 102, name: 'bar'}, {attributeGroupId: 2, attributeId: 12, name: 'Square'}, {attributeGroupId: 3, attributeId: 103, name: 'baz'}]


console .log ('Original:', regroupAtts (atts))
console .log ('With third group added:', regroupAtts (atts2))
代码语言:javascript
运行
复制
.as-console-wrapper {max-height: 100% !important; top: 0}

我们添加了第三个属性,包括名称"foo""bar""baz",以说明如何将其扩展到更多的属性。当然,如果添加太多这样的属性,您将不得不考虑组合爆炸,但是代码是为了处理它而设计的。

这里有趣的抽象是,如果您想参数化名称"attributeGroupId""attributeId""name"。我们可以选择这样做:

代码语言:javascript
运行
复制
const regroup = (key, props) => (xs) => 
  cartesian (group (x => x [key]) (xs))
    .map (xs => Object .fromEntries (
      props .map (prop => [prop, xs .map (x => x [prop]) .join ('-')])
    ))

const regroupAtts = regroup ('attributeGroupId', ['attributeId', 'name']) 

代码语言:javascript
运行
复制
const cartesian = ([xs, ...xss]) =>
  xs == undefined ? [[]] : xs .flatMap (x => cartesian (xss) .map (ys => [x, ...ys]))

const group = (fn, k) => (xs) => Object .values (xs .reduce (
  (a, x) => ((k = 'x' + fn (x)), (a [k] = a[k] || []), (a[k] .push (x)), a), {}
))

const regroup = (key, props) => (xs) => 
  cartesian (group (x => x [key]) (xs))
    .map (xs => Object .fromEntries (
      props .map (prop => [prop, xs .map (x => x [prop]) .join ('-')])
    ))

const regroupAtts = regroup ('attributeGroupId', ['attributeId', 'name']) 


const atts = [{attributeGroupId: 2, attributeId: 11, name: 'Diamond'}, {attributeGroupId: 1, attributeId: 9, name: '916'}, {attributeGroupId: 1, attributeId: 1, name: '24K'}, {attributeGroupId: 2, attributeId: 12, name: 'Square'}]
const atts2 = [{attributeGroupId: 2, attributeId: 11, name: 'Diamond'}, {attributeGroupId: 1, attributeId: 9, name: '916'}, {attributeGroupId: 3, attributeId: 101, name: 'foo'}, {attributeGroupId: 1, attributeId: 1, name: '24K'}, {attributeGroupId: 3, attributeId: 102, name: 'bar'}, {attributeGroupId: 2, attributeId: 12, name: 'Square'}, {attributeGroupId: 3, attributeId: 103, name: 'baz'}]

console .log ('Original:', regroupAtts (atts))
console .log ('With third group added:', regroupAtts (atts2))
代码语言:javascript
运行
复制
.as-console-wrapper {max-height: 100% !important; top: 0}

以这种方式编写它,我们现在有了可重用的cartesiangroup函数,这些函数经常出现。事实上,我从我以前写的答案里偷了这些。(我确实通过将group添加到密钥生成中来稍微改变了'x' +。这是因为您的密钥(attributeGroupIds)是简单的数字。当Object.values像这样迭代一个对象时,它首先按数字顺序执行这些操作,然后按插入顺序迭代剩余的字符串键,然后按符号进行迭代。通过在字符串前面加上一个字符串,我将所有这些都按插入顺序排列,并返回您所喜欢的顺序。我试图弄清楚这个函数的这个变体是否取代了我通常工具箱中的那个。)

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/73834942

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档