группировать объекты на основе значения - PullRequest
1 голос
/ 23 апреля 2019

Уже несколько часов тяну меня за волосы, так что пришло время получить помощь от 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]
}

Моя первоначальная мысль заключалась в том, что мне нужно пройтись по каждому элементу и сравнить его со следующим, так что сначала я посмотрел на уменьшение, но не смог сделать это правильно, поэтому я начал цикл поэлементы в массиве data и сравнение его со следующим (получая индекс из map и увеличивая его, чтобы увидеть следующий элемент, но это выглядит очень странно.

algo's и CS не моисильная сторона, но я чувствую, что способ, которым я делаю это, грязен, и что уже есть шаблон для этого, так как это должно быть обычной задачей

Мой следующий подход будет заключаться в цикле каждого добавления, добавления чего-либо к даннымтакие как grouping id, то есть group: 1, сохраняют приращение и просто ++, когда surname не соответствует предыдущему, но это все равно не звучит "оптимально" в качестве идентификатора, тогданужно набрать filter для каждой группы, чтобы получить данные в правильном формате.

NB Я видел несколько связанных с этим вопросов SO, связанных с моей проблемой, но они упускают важный фактор необходимости сортировкипо динамическому значению, это простая задача, если известны значения

Любое руководство будет с благодарностью

Спасибо

Ответы [ 5 ]

2 голосов
/ 23 апреля 2019

Есть много способов сделать это. 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 голос
/ 23 апреля 2019

Вы можете использовать groupBy из lodash:

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' } ] }
1 голос
/ 23 апреля 2019

Использование комбинации списка уникальных ключей (с дублированием с использованием Set), reduce, map и filter работает:

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);
0 голосов
/ 23 апреля 2019

Для достижения ожидаемого результата используйте уменьшение и добавление объектов на основе фамилии ключа

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

0 голосов
/ 23 апреля 2019

Как вы хотите обращаться с людьми с одинаковыми фамилиями, которые не встречаются непрерывно. Например: Джонс, Джонс, Смит, Джонс?

Если вы хотите сгруппировать их все, используйте 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);
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...