根据对象数组中的重复值将对象分组

3
这是对象的输入数组:
var array = [{
    id: 1,
    name: 'A',
    family: 'B',
    number: 100,
    category: 'test',
    time: '2018-03-02T10:33:00.000Z'
  },
  {
    id: 2,
    name: 'A',
    family: 'B',
    number: 100,
    category: 'test',
    time: '2018-03-02T10:33:50.000Z'
  },
  {
    id: 3,
    name: 'A',
    family: 'B',
    number: 100,
    category: 'test',
    time: '2018-03-02T10:34:30.000Z'
  },
  {
    id: 4,
    name: 'A',
    family: 'B',
    number: 100,
    category: 'test',
    time: '2018-03-02T10:36:00.000Z'
  },
  {
    id: 5,
    name: 'A',
    family: 'C',
    number: 250,
    category: 'other',
    time: '2018-03-02T10:33:00.000Z'
  },
  {
    id: 6,
    name: 'A',
    family: 'C',
    number: 250,
    category: 'other',
    time: '2018-03-02T10:33:05.000Z'
  }
]

我希望将输出结果分组,如下所示:

var output = [
  [{
      id: 1,
      name: 'A',
      family: 'B',
      number: 100,
      category: 'test',
      time: '2018-03-02T10:33:00.000Z'
    },
    {
      id: 2,
      name: 'A',
      family: 'B',
      number: 100,
      category: 'test',
      time: '2018-03-02T10:33:50.000Z'
    },
    {
      id: 3,
      name: 'A',
      family: 'B',
      number: 100,
      category: 'test',
      time: '2018-03-02T10:34:30.000Z'
    },
    {
      id: 4,
      name: 'A',
      family: 'B',
      number: 100,
      category: 'test',
      time: '2018-03-02T10:36:00.000Z'
    }
  ],
  [{
      id: 5,
      name: 'A',
      family: 'C',
      number: 250,
      category: 'other',
      time: '2018-03-02T10:33:00.000Z'
    },
    {
      id: 6,
      name: 'A',
      family: 'C',
      number: 250,
      category: 'other',
      time: '2018-03-02T10:33:05.000Z'
    }
  ]
]

如您所见,只有id和time是唯一的,我想根据重复的name、family、number和category分组。因此,所有具有相同name、family、number和category值的对象应该有一个单独的数组。
我尝试了很多方法,使用了两个嵌套的for循环,使用了map和filter,我尽我所能,但我无法做到!
如果有人能在这方面帮忙,我真的非常感激。

1
请展示代码,因为现在这个问题听起来像“为我做这件事”。 - An0num0us
3个回答

4
你可以使用 Map 将同一组的所有项收集到一个数组中。
稍后只需获取地图的值作为结果即可。
这仅适用于一个分组 category

var array = [{ id: 1, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:33:00.000Z' }, { id: 2, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:33:50.000Z' }, { id: 3, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:34:30.000Z' }, { id: 4, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:36:00.000Z' }, { id: 5, name: 'A', family: 'C', number: 250, category: 'other', time: '2018-03-02T10:33:00.000Z' }, { id: 6, name: 'A', family: 'C', number: 250, category: 'other', time: '2018-03-02T10:33:05.000Z' }],
    grouped = Array.from(array.reduce((m, o) =>
        m.set(o.category, (m.get(o.category) || []).concat(o)), new Map).values());

console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }

如果有多个组,您可以使用闭包为 key 取一个包含实际对象的 namefamilynumbercategory 值的联合键。

然后映射新的数组与关闭时间并将所有数组合并为单个嵌套数组。最后按长度过滤。

var array = [{ id: 1, sourceAccount: "A", targetAccount: "B", amount: 100, category: "eating_out", time: "2018-03-02T10:33:00.000Z" }, { id: 2, sourceAccount: "A", targetAccount: "B", amount: 100, category: "eating_out", time: "2018-03-02T10:33:50.000Z" }, { id: 3, sourceAccount: "A", targetAccount: "B", amount: 100, category: "eating_out", time: "2018-03-02T10:34:30.000Z" }, { id: 4, sourceAccount: "A", targetAccount: "B", amount: 100, category: "eating_out", time: "2018-03-02T10:36:00.000Z" }, { id: 5, sourceAccount: "A", targetAccount: "C", amount: 250, category: "other", time: "2018-03-02T10:33:00.000Z" }, { id: 6, sourceAccount: "A", targetAccount: "C", amount: 250, category: "other", time: "2018-03-02T10:33:05.000Z" }],
    groupBy = ['name', 'family', 'number', 'category'],
    result = Array
        .from(
            array
                .reduce((m, o) => (k => m.set(k, (m.get(k) || []).concat(o)))(groupBy.map(k => o[k]).join('|')), new Map)
                .values(),
            o => o.sort((a, b) => a.time.localeCompare(b.time))
        )
        .map(g => g.reduce((r, o, i, a) => {
            if (!i || new Date(o.time).getTime() - new Date(a[i - 1].time).getTime() > 60000) {
                r.push([o]);
            } else {
                r[r.length - 1].push(o);
            }
            return r;
        }, []))
        .reduce((r, a) => r.concat(a), [])
        .filter(a => a.length > 1);

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }


谢谢你,Nina。这正是我需要的,非常感激。 - Emad Dehnavi
我能在这里比较时间属性值吗?比如说,如果我想仅在每个对象之间的时间差小于1分钟时进行分组,我知道如何获取时间差,但是使用您的解决方案,我有点困惑应该在哪里应用它? - Emad Dehnavi
这个请求的解决方案比以前要复杂一些,因为您需要为每个键提供特殊处理。在这种情况下,一个带有各种情况函数的对象将更好且更易于维护。您最后一句话的意思是什么?您是否只需要至少有两个元素的条目? - Nina Scholz
正确,至少有两个元素,比如我们再加入另一个条目,例如类别为“食品”,名称为“A”,家庭为“T”,数字为334,这不应该被分组。关于时间,我可以使用分组数组并在其上执行另一个reduce操作,然后从那里进行比较吗? - Emad Dehnavi
不,它没有排序,在获取所需输出后,我需要使用升序排序。基本上,我需要列出所有重复的对象组,并列出每个连续对象之间的时间差(如果小于1分钟)。按时间升序排列,格式为(output [] [])。 - Emad Dehnavi
显示剩余4条评论

3

只需使用 Array.reduce() 创建一个地图,其中包含name, family,number和category的组合键。 然后,您可以在该地图上使用Object.values()来获取所需的结果。

var array =[ { id: 1, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:33:00.000Z' }, { id: 2, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:33:50.000Z' }, { id: 3, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:34:30.000Z' }, { id: 4, name: 'A', family: 'B', number: 100, category: 'test', time: '2018-03-02T10:36:00.000Z' }, { id: 5, name: 'A', family: 'C', number: 250, category: 'other', time: '2018-03-02T10:33:00.000Z' }, { id: 6, name: 'A', family: 'C', number: 250, category: 'other', time: '2018-03-02T10:33:05.000Z' } ];

var result = Object.values(array.reduce((a,curr)=>{
  const {name, family, number, category} = curr;
  const key = `${name}_${family}_${number}_${category}`;
  (a[key] = a[key] || []).push(curr);
  return a;
},{}));

console.log(result);


不要只是将 curr.name+curr.family+curr.number+curr.category 直接相加,我会在每个项目之间放置某种分隔符,例如分号或其他原始数据中不太可能出现的字符。 - kshetline
@kshetline 感谢您的建议。已更新答案 :-) - amrender singh

1
您也可以使用Array.reduce()来获得该输出:

var array = [ { id: 1,
  name: 'A',
  family: 'B',
  number: 100,
  category: 'test',
  time: '2018-03-02T10:33:00.000Z' },
  { id: 2,
  name: 'A',
  family: 'B',
  number: 100,
  category: 'test',
  time: '2018-03-02T10:33:50.000Z' },
  { id: 3,
  name: 'A',
  family: 'B',
  number: 100,
  category: 'test',
  time: '2018-03-02T10:34:30.000Z' },
  { id: 4,
  name: 'A',
  family: 'B',
  number: 100,
  category: 'test',
  time: '2018-03-02T10:36:00.000Z' },
  { id: 5,
  name: 'A',
  family: 'C',
  number: 250,
  category: 'other',
  time: '2018-03-02T10:33:00.000Z' },
  { id: 6,
  name: 'A',
  family: 'C',
  number: 250,
  category: 'other',
  time: '2018-03-02T10:33:05.000Z' } 

];

var res = array.reduce((acc, obj)=>{
  var existObj;
  for(var i = 0 ; i < acc.length; i++) {
    let accArray = acc[i];
    if(accArray){
     existObj = accArray.find(({name, family, number, category}) =>  name == obj.name && family == obj.family && number == obj.number && category == obj.category);
     if(existObj) {
        accArray.push(obj);
        return acc;
     }
    }
 }
  acc.push([obj]);
  return acc;
}, []);
console.log(res);


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