сгруппируйте массив объектов по идентификатору

#javascript #arrays #json #sorting #object

Вопрос:

Я пытаюсь перебрать массив объектов и сгруппировать элементы массива в новые массивы с соответствующим идентификатором:

Пример API:

     api_array [
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
   ];
 

Я пытаюсь достичь этого результата:

 result [
group_one [
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
]
group_two [
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
]
group_three [
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
]
group_four [
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
]
]
 

Мне действительно удалось этого достичь, но я думаю, что это безумие, и я уверен, что есть лучшая реализация, вот что я сделал:

 const createAddresses = (address) => {


        let group_one= [],
        group_two = [],
        group_three = [],
        group_four = [],
          group = [];

        debugger;
        for(let i=0; i < address.length; i  ) {             
            switch (address[i].id) {
                case 1:
                        group_one.push(address[i]);
                    break;
                case 2:
                        group_two.push(address[i]);
                    break;
                case 3:
                        group_three.push(address[i]);
                    break;
                case 4:
                        group_four.push(address[i]);
                    break;
                default:
                    return address;                
            }
        }



        console.log('GROUP', group);
        return group.push(group_one, group_two, group_three, group_four);
    }
 

Мне действительно не нравится эта реализация, и я попробовал это:

 const obj = address.reduce((acc, cur) => ({...acc, [cur.id]: cur}), {});
 

и то, что выше, делает то же самое, что и моя безумная функция цикла, но она добавляет только последний элемент для каждой группы, например:

 result [
    0 [
           {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    ]
    1 [
           {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    ]
    2 [
           {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    ]
    3 [`enter code here`
           {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    ]
    ]
 

но, как я уже упоминал, мне нужны все элементы в каждой группе, пожалуйста, любые советы.

Комментарии:

1. Я предлагаю не изобретать велосипед заново: groupBy , хотя, конечно, вы можете написать его сами, если захотите. Вы также можете посмотреть на источник lodash, если вам нужно вдохновение, хотя они подходят для более сложных сценариев и используют свои собственные служебные функции.

2. Итак, подождите, вам нужен массив массивов или объект с ключами типа «group_1», сопоставленный с массивом?

Ответ №1:

сгруппируйте массив объектов по идентификатору

 //Create a javascript array of objects containing key value pairs id, post 
var api_array = [ 
       {id: 1, postcode: '10'}, 
       {id: 1, postcode: '11'}, 
       {id: 2, postcode: '20'}, 
       {id: 2, postcode: '21'}, 
       {id: 2, postcode: '22'}, 
       {id: 3, postcode: '30'} 
   ];  
//result is a javascript array containing the groups grouped by id. 
let result = []; 

//javascript array has a method foreach that enumerates keyvalue pairs. 
api_array.forEach(  
    r => { 
        //if an array index by the value of id is not found, instantiate it. 
        if( !result[r.id] ){  
            //result gets a new index of the value at id. 
            result[r.id] = []; 
        } 
        //push that whole object from api_array into that list 
        result[r.id].push(r); 
    }   
); 
console.log(result[1]); 
console.log(result[2]); 
console.log(result[3]);
 

С принтами:

 [ { id: 1, postcode: '10' }, { id: 1, postcode: '11' } ]

[ { id: 2, postcode: '20' }, 
  { id: 2, postcode: '21' },
  { id: 2, postcode: '22' } ]

[ { id: 3, postcode: '30' } ]
 

Комментарии:

1. Мне нравится этот ответ, потому что он соответствует желанию OPs иметь массив массивов, но единственное, что я хотел бы добавить, это то, что они могут захотеть рассмотреть возможность удаления плавающего пустого элемента массива с индексом 0 с чем-то вроде result = result.filter(() => true);

Ответ №2:

Попытайтесь достичь такого:

  

  var api_array = [
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
   ];
   
  const result = api_array.reduce((acc, item) => {
    acc[`group_${item.id}`] = (acc[`group_${item.id}`] || []);
    acc[`group_${item.id}`].push(item);
    return acc;
  }, {});

console.log(result); 

Примечание: В результате будут получены ключи group_1 , group_2 … вместо group_one этого , group_two

Если вам это строго необходимо, создайте массив для ключей и значений, чтобы преобразовать 1 в единицу.

Ответ №3:

https://jsfiddle.net/u4k16ojz/5/

 var result = new Array(4);
api_array.forEach(function(item, index){
  if (!result[item.id]){
    result[item.id] = [];
  }
  result[item.id].push(item);
})
 

Комментарии:

1. Это, по сути, тот же ответ, что и у меня, хотя вы использовали более старый синтаксис стиля и включили индекс, который не используется. Мне все же любопытно, что он 4?

2. Намерение состояло в том, чтобы указать начальную длину массива, но в JS это нужно сделать по-другому. Я обновил пример. Спасибо за обратную связь.

Ответ №4:

 var objs = [
   { id: 1, postcode: "xxx", street: "xxx", city: "xxx" },
   { id: 1, postcode: "xxx", street: "xxx", city: "xxx" },
   { id: 2, postcode: "xxx", street: "xxx", city: "xxx" },
   { id: 3, postcode: "xxx", street: "xxx", city: "xxx" }
];

var result = objs.reduce(function(r, a) {
  r[a.id] = r[a.id] || [];
  r[a.id].push(a);
  return r;
}, Object.create(null));

console.log(result); 

Комментарии:

1. Код должен быть самодокументированным, это меня смущает.

Ответ №5:

Вы можете взять Map для группировки то же id самое и получить значения с карты в качестве результирующего набора.

Результирующий набор имеет тот же порядок нужных ключей.

 function groupBy(array, key) {
    return Array.from(array
        .reduce((m, o) => m.set(o[key], [...(m.get(o[key]) || []), o]), new Map)
        .values()
    );
}

var data = [{ id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx' }, { id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx' }],
    grouped = groupBy(data, 'id');

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

Ответ №6:

Как и в вашем reduce примере, это повторяет данные и создает объект, используя идентификаторы объектов в качестве ключей и группируя их вместе. Затем он извлекает значения из этого объекта.

 const api_array = [{id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},{id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'}];

const out = Object.values(api_array.reduce((acc, c) => {
  const { id } = c;

  // If the object doesn't have a key that matches the id
  // create an array as its value and then concat the current object
  // to it, otherwise, if the key exists just concat the current object
  // to the existing array
  acc[id] = (acc[id] || []).concat(c);
  return acc;
}, {}));

console.log(out) 

Ответ №7:

Вы можете использовать идентификаторы в качестве свойств объекта

 let api_array = [
    {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
    {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
];

let grouped = groupArray(api_array);

console.log(grouped);
console.log(grouped[1]);

function groupArray(myArray) {
    let grouped = {};

    for (let i = 0; i < myArray.length; i  ) {
        let row = myArray[i];
        let group = grouped[row.id];
        if (!group) {
            group = [];
            grouped[row.id] = group;
        }
        group.push(row);
    }

    return grouped;
}
 

Ответ №8:

 api_array [
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 1, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 2, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 3, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
       {id: 4, postcode: 'xxx', street: 'xxx', city: 'xxx'},
];

let result = [];
for (let i = 0; i < numberOfGroupsIWantToMake; i  ) {
    let newGroupArray = api_array.filter(obj => obj.id === i);
    result.push(newGroupArray);
}

return resu<
 

Примечание: это решение, но оно не так эффективно, как если бы мы просматривали весь массив n раз.

Комментарии:

1. Сложность O(n^2)