Нужен эффективный способ сгруппировать массив объектов в JavaScript - PullRequest
0 голосов
/ 02 ноября 2018

Есть ли способ сгруппировать массив объектов, ссылаясь на определенное значение объекта в массиве

допустим, у меня есть массив с именем

a=[
{name: "abc", address: "xxx"}
{name: "def", address: "yyy"}
{name: "xyz", address: "xyz"}
{name: "abc", address1: "123"}
{name: "def", address1: "456"}
]

Мне нужно добавить адрес с тем же именем в один объект, и новый массив должен выглядеть так, как показано ниже

b =[
{name:"abc", address: "xxx", address1: "123"}
{name:"def", address: "yyy", address1: "456"}
{name: "xyz", address: "xyz"}
]

Ответы [ 6 ]

0 голосов
/ 03 ноября 2018

Это ответ с использованием Rxjs:

import { from } from 'rxjs';
import { groupBy, mergeMap, toArray, map, reduce } from 'rxjs/operators';

interface IPerson{
    name: string;
    address?: string;
    address1?: string;
}

let a:IPerson[]=[
        {name: "abc", address: "xxx"},
        {name: "def", address: "yyy"},
        {name: "xyz", address: "xyz"},
        {name: "abc", address1: "123"},
        {name: "def", address1: "456"},
    ]


let personSource = from(a);

personSource.pipe(
        groupBy(x => x.name),
        mergeMap(g => g.pipe(
            reduce((acc:IPerson, val:IPerson) => {
                acc.name = val.name;
                if(val.address1) acc.address1 = val.address1;
                if(val.address) acc.address = val.address;

                return acc;
            })    
        ))
    )
    .subscribe(y => {
        console.log(y);
    })
0 голосов
/ 02 ноября 2018

Это функциональный подход для решения всей проблемы. Смотрите комментарии, чтобы понять, как это работает!

const a = [{
  name: "abc",
  address: "xxx"
}, {
  name: "def",
  address: "yyy"
}, {
  name: "xyz",
  address: "xyz"
}, {
  name: "abc",
  address: "123"
}, {
  name: "def",
  address: "456"
}]
    
const map = f => xs => xs.map (f)
    
const pipe = xs => x => 
      xs.reduce ((x, f) => f (x), x)

const objectFromEntries = xs => 
      xs.reduce ((o, [prop, value]) => ({ ...o, [prop]: value }), {})
      

const groupBy = prop => xs => 
      xs.reduce ((o, x) => 
         ({ ...o, [x[prop]]: [...(o[x[prop]] || []), x] })
      , [])
    
const addressPairs = map (({ address }, i) => 
      [`address${i + 1}`, address]
)
    
const organizeByName = pipe ([
   groupBy ('name'), // (1) Groups by name the whole objects
   Object.entries, // (2) Turns groups into pairs
   map (([name, xs]) => // (3) Flattens group entry's addresses
       [['name', name], ...addressPairs (xs)]
   ),
   map (objectFromEntries) // (4) Turns each flattened group into an object
])

const output = organizeByName (a)

console.log (output)
0 голосов
/ 02 ноября 2018

Вы можете использовать " Object.Values ​​" и " Reduce ", чтобы добиться этого, как показано ниже

var a=[
    {name: "abc", address: "xxx"}
    , {name: "def", address: "yyy"}
    , {name: "xyz", address: "xyz"}
    , {name: "abc", address1: "123"}
    , {name: "def", address1: "456"}
]

var result = Object.values(a.reduce(
                            (o,d) => (
                                       o[d.name] = { ...d, ...(o[d.name] && o[d.name]) }
                                       , o
                                     )
                            , {})
                           )

console.log(result)
0 голосов
/ 02 ноября 2018

Я знаю, что у вас уже есть хороший ответ, но я хотел показать вам другой способ.

Я бы сохранил его как один ключ вместо address1 и т. Д. И использовал бы его значение в качестве списка всех адресов.

Чтобы ваш результат выглядел так:

[ { name: 'abc', address: [ 'xxx', '123' ] },
  { name: 'def', address: [ 'yyy', '456' ] },
  { name: 'xyz', address: [ 'xyz' ] } ]

a=[
  {name: "abc", address: "xxx"},
  {name: "def", address: "yyy"},
  {name: "xyz", address: "xyz"},
  {name: "abc", address: "123"},
  {name: "def", address: "456"}
]

new_array = a.reduce((agg, item) => {
  const index = agg.findIndex(find_item => find_item.name === item.name)
  if (index !== -1) {
    agg[index].address.push(item.address)
  } else {
    agg.push({ name: item.name, address: [item.address] })
  }
  return agg
},[])

console.log(new_array)
/*
[ { name: 'abc', address: [ 'xxx', '123' ] },
  { name: 'def', address: [ 'yyy', '456' ] },
  { name: 'xyz', address: [ 'xyz' ] } ]
*/
0 голосов
/ 02 ноября 2018

Вы можете использовать пары значений ключей для отслеживания значений и использовать метод delete для удаления значений

0 голосов
/ 02 ноября 2018

Вы можете использовать функцию reduce для группировки по имени и функцию Object.values для извлечения сгруппированных объектов.

let a = [{name: "abc", address: "xxx"},{name: "def", address: "yyy"},{name: "xyz", address: "xyz"},{name: "abc", address1: "123"},{name: "def", address1: "456"}],
    result = Object.values(a.reduce((a, {name, ...rest}) => {
      a[name] = Object.assign(a[name] || {name}, rest);
      return a;
    }, Object.create(null)));

console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...