根据值对对象进行分组

时间:2019-04-23 20:24:53

标签: javascript javascript-objects

现在我拉了几个小时,所以有时间从SO那里寻求帮助

我有一个对象数组,像这样:

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"}
];
// Actual data is much more complex, this is just a simplified example

我基本上是尝试根据字段(在此示例surname中)对数据进行分组。姓氏值事先未知,因此需要动态。因此,您将查看数组中的下一项,如果它与分组的前一项匹配,则但是如果不匹配,则它将开始一个新的组。

最终结果看起来像这样:

const outcome = {
  jones: [...2 objects],
  smith: [...2 objects],
  clarkson: [...1 objects],
  walker: [...2 objects],
  fletcher: [...1 objects]
}

我最初的想法是,我需要遍历每个项目并将其与下一个项目进行比较,因此最初着眼于reduce但无法正确实现,因此我开始遍历data数组中的项目,然后将其与下一个进行比较(通过从map获取索引并对其进行递增以查看下一个项目,但这确实很麻烦。

algo和CS并不是我的强项,但我觉得我做这件事的方式很脏,而且已经有一种模式,因为它必须是一项常见任务

我的下一个方法是遍历每个添加项,向数据中添加一些内容,例如grouping id,即group: 1,保持增量,++仅在{{ 1}}与前一个不匹配,但是作为id听起来仍然不是“最优”,因此必须在每个组上运行surname才能以正确的格式获取数据。

N.B。我已经看到了几个与我的问题相关的SO问题,但它们错过了必须按动态值排序的重要因素,如果知道这些值,这是一件容易的事

任何指导将不胜感激

谢谢

5 个答案:

答案 0 :(得分:2)

有很多方法可以做到这一点。我想到的reduce是最好的。

请参见以下代码段:

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"}
];

function group(array,field){
    return array.reduce((acc,elem)=>{
        //whether the field value exist
        if(acc[elem[field]]){
            //if the field value exist, push elem to it:
            acc[elem[field]].push(elem)
        }else{
            //if the field value doesn't exist, create an array with elem:
            acc[elem[field]]=[elem]
        }
        //return accumulator for later use
        return acc
    },{})
}

const outcome = group(data,"surname")

console.log(outcome)

答案 1 :(得分:1)

您可以使用lodash中的groupBy

import { groupBy } from 'lodash'

const result = groupBy(data, item => item.surname)

结果将是:

{ jones:
   [ { city: 'London', surname: 'jones' },
     { city: 'Manchester', surname: 'jones' } ],
  smith:
   [ { city: 'Leeds', surname: 'smith' },
     { city: 'Birmingham', surname: 'smith' } ],
  clarkson: [ { city: 'Rhyl', surname: 'clarkson' } ],
  walker:
   [ { city: 'Blackpool', surname: 'walker' },
     { city: 'Rhyl', surname: 'walker' } ],
  fletcher: [ { city: 'Blackpool', surname: 'fletcher' } ] }

答案 2 :(得分:1)

使用唯一键列表(使用Set进行重复数据删除),reducemapfilter的组合可以有效:

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"}
];

const result = [...new Set(data.map(x => x.surname))]
  .reduce((acc, val) => { 
    return {...acc, [val]: [...(data
        .filter(x => x.surname === val)
        .map(x => { return { city: x.city } }))]};
  }, {});

console.log(result);

答案 3 :(得分:0)

您要如何处理姓氏不连续的人。例如:琼斯,琼斯,史密斯,琼斯?

如果您想将它们全部分组,reduce本质上就是为此用例而设计的,它的使用非常简单:

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"}
];

let grouped = data.reduce((acc, d) => {
  acc[d.surname] = acc[d.surname] || [];
  acc[d.surname].push(d.city);
  return acc;
}, {});

console.log(grouped);

如果您想覆盖以前相同姓氏的序列(例如jones, jones, smith, jones将映射到1个史密斯和1个(最后一个)琼斯),那么您还可以跟踪迭代的前一个人并进行比较姓:

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"},
  {city: "non-continuous jones", surname: "jones"},
];

let grouped = data.reduce(([acc, prevSurname], d) => {
  if (prevSurname !== d.surname)
    acc[d.surname] = [];
  acc[d.surname].push(d.city);
  return [acc, d.surname];
}, [{}])[0];

console.log(grouped);

答案 4 :(得分:0)

要达到预期效果,请根据姓氏键使用减少和添加对象

const data = [
  {city: "London", surname: "jones"},
  {city: "Manchester", surname: "jones"},
  {city: "Leeds", surname: "smith"},
  {city: "Birmingham", surname: "smith"},
  {city: "Rhyl", surname: "clarkson"},
  {city: "Blackpool", surname: "walker"},
  {city: "Rhyl", surname: "walker"},
  {city: "Blackpool", surname: "fletcher"}
];

console.log(data.reduce((acc,v)=> {
   acc[v.surname]? (acc[v.surname].push(v)) : (acc[v.surname] =[v])
  return acc
}, {}))

codepen-https://codepen.io/nagasai/pen/EJdamx?editors=1010