#javascript #arrays #json #object #ecmascript-6
#javascript #массивы #json #объект #ecmascript-6
Вопрос:
Здесь много подобных вопросов, но я не смог найти тот, который соответствовал бы моим потребностям. Я ищу относительно простое решение о том, как складывать объекты из массива в новые массивы на основе ключа.
В примере данных мы группируем объекты по их ключу «ship».
Исходные данные:
var myObjArray = [
{
name:'Malcolm Reynolds',
ship:'Serenity'
},
{
name: 'Carmen Ibanez',
ship: 'Rodger Young',
},
{
name: 'Zander Barcalow',
ship: 'Rodger Young',
},
{
name:'Hoban Washburne',
ship:'Serenity'
},
{
name:'James Kirk',
ship:'USS Enterprise'
}
];
Реструктурированные данные:
var myNewObjArray = [
[{
name:'Malcolm Reynolds',
ship:'Serenity'
},
{
name:'Hoban Washburne',
ship:'Serenity'
}],
[{
name: 'Carmen Ibanez',
ship: 'Rodger Young',
},
{
name: 'Zander Barcalow',
ship: 'Rodger Young',
}],
{
name:'James Kirk', // optionally also stick in an array
ship:'USS Enterprise'
}
];
Если у кого-нибудь есть решение для этого, я был бы признателен, моя нынешняя попытка, мягко говоря, неаккуратна.
Комментарии:
1. пожалуйста, добавьте свою попытку. почему последний элемент не заключен в массив?
2. используйте
.sort(customCompare)
гдеcustomCompare = function(a,b){.....}
Ответ №1:
Вы можете использовать объект для и ship
значение в качестве ключа для одной и той же группы. Для результата берутся только значения объекта.
var data = [{ name: 'Malcolm Reynolds', ship: 'Serenity' }, { name: 'Carmen Ibanez', ship: 'Rodger Young' }, { name: 'Zander Barcalow', ship: 'Rodger Young' }, { name: 'Hoban Washburne', ship: 'Serenity' }, { name: 'James Kirk', ship: 'USS Enterprise' }],
grouped = Object.values(data.reduce((r, o) => {
if (!r[o.ship]) {
r[o.ship] = o;
return r;
}
if (!Array.isArray(r[o.ship])) r[o.ship] = [r[o.ship]];
r[o.ship].push(o);
return r;
}, {}));
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Подход с Map
var data = [{ name: 'Malcolm Reynolds', ship: 'Serenity' }, { name: 'Carmen Ibanez', ship: 'Rodger Young' }, { name: 'Zander Barcalow', ship: 'Rodger Young' }, { name: 'Hoban Washburne', ship: 'Serenity' }, { name: 'James Kirk', ship: 'USS Enterprise' }],
grouped = Array.from(
data
.reduce((m, o) => m.set(o.ship, [...(m.get(o.ship) || []), o]), new Map)
.values(),
a => a.length === 1 ? a[0] : a
);
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Комментарии:
1. Спасибо, Нина, мне нравится использовать reduce, я этого не учел.
2. Это принятый ответ, потому что мои данные были намного сложнее, чем в примере, и я смог быстро изменить их в соответствии со своими потребностями, что, как я полагаю, сделают и другие (просто нужно было добавить дополнительную карту для сопоставления с другим значением
item.ship
, если оно не существовало).
Ответ №2:
Найдите и дедуплицируйте названия кораблей, затем найдите персонал для каждого корабля.
const myObjArray = [
{
name:'Malcolm Reynolds',
ship:'Serenity'
},
{
name: 'Carmen Ibanez',
ship: 'Rodger Young',
},
{
name: 'Zander Barcalow',
ship: 'Rodger Young',
},
{
name:'Hoban Washburne',
ship:'Serenity'
},
{
name:'James Kirk',
ship:'USS Enterprise'
}
];
const ships = myObjArray.map(({ship}) => ship).filter((ship, i, arr) => arr.indexOf(ship) === i);
const personnelArray = ships.map(ship => myObjArray.filter(entry => entry.ship === ship));
console.log(personnelArray);
Комментарии:
1. Супер просто и чисто спасибо … в моей версии было задействовано 3 массива, которые я пытался сопоставить с оригиналом, один с just ships, затем новый, основанный на индексах just ships…
Ответ №3:
Другим чистым и элегантным решением было бы работать с Lodash.
Сначала сгруппируйте по массиву с соответствующим ключом.Затем получите значения из объекта.
Из документации :
Создает объект, состоящий из ключей, сгенерированных по результатам выполнения каждого элемента коллекции через итерацию. Порядок сгруппированных значений определяется порядком их появления в коллекции. Соответствующее значение каждого ключа представляет собой массив элементов, отвечающих за генерацию ключа. Итерация вызывается с одним аргументом: (значение).
const myObjArray = [
{
name:'Malcolm Reynolds',
ship:'Serenity'
},
{
name: 'Carmen Ibanez',
ship: 'Rodger Young',
},
{
name: 'Zander Barcalow',
ship: 'Rodger Young',
},
{
name:'Hoban Washburne',
ship:'Serenity'
},
{
name:'James Kirk',
ship:'USS Enterprise'
}
];
var result =_.values((_.groupBy(myObjArray , 'ship')));
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.16.4/lodash.min.js"></script>
Ответ №4:
Вероятно, не самый эффективный, но это должно сработать.
var tempObj = {};
myObjArray.forEach((item)=>{
var ship = item.ship;
if (!tempObj.hasOwnProperty(ship)) {
tempObj[ship] = []; //create the key in the key in the obj and init to an empty array
}
tempObj[ship].push(item); //add the item to the array
});
var myNewObjArray = [];
for (key in tempObj) {
myNewObjArray.push([]); //add a new array for each key in the tempObj
tempObj[key].forEach((item)=>{ //iterate over the array of items in the tempObj for that key
myNewObjArray[myNewObjArray.length-1].push(item); //add the item to the last array in the object which should have been created.
});
}
Комментарии:
1. Спасибо, Гарри, недалеко от того, что я собрал, но немного чище.
Ответ №5:
Это немного отличается тем, что это объект с ключами, но эти ключи содержат массивы с данными, как вы хотите их видеть.
var newObject = {};
for (var i in myObjArray) {
var newKey = myObjArray[i].ship.replace(/s /g, '');
if (typeof(newObject[newKey]) == "undefined") newObject[newKey] = [];
newObject[newKey].push({
name: myObjArray[i].name, ship: myObjArray[i].ship
});
}
Ответ №6:
Не уверен, как вы планируете использовать данные, но будет ли более сжатая структура данных выглядеть как объект, где на корабле есть персонал, а не массив массивов, где название корабля постоянно повторяется избыточным образом? Что насчет этой структуры данных?
var myObjArray = [
{
name:'Malcolm Reynolds',
ship:'Serenity'
},
{
name: 'Carmen Ibanez',
ship: 'Rodger Young',
},
{
name: 'Zander Barcalow',
ship: 'Rodger Young',
},
{
name:'Hoban Washburne',
ship:'Serenity'
},
{
name:'James Kirk',
ship:'USS Enterprise'
}
];
const staffShips = data => data.reduce((ships, item) => {
const ship = ships[item.ship];
if (ship) {
ship.push(item.name);
} else {
ships[item.ship] = [ item.name ];
}
return ships;
}, {});
console.log(staffShips(myObjArray));
Ответ №7:
Здесь у вас есть другой подход, сначала мы используем Array.reduce() для создания объекта, который будет группировать элементы по свойству ship . Затем мы используем Array.map() поверх сгенерированного Object.values(), чтобы удалить массив, если содержит только один элемент. Карта может быть необязательной, если вам действительно не нужен этот последний шаг.
var myObjArray = [
{name:'Malcolm Reynolds', ship:'Serenity'},
{name: 'Carmen Ibanez', ship: 'Rodger Young'},
{name: 'Zander Barcalow', ship: 'Rodger Young'},
{name:'Hoban Washburne', ship:'Serenity'},
{name:'James Kirk', ship:'USS Enterprise'}
];
let res = myObjArray.reduce((acc, obj) =>
{
acc[obj.ship] = acc[obj.ship] || [];
acc[obj.ship].push(obj);
return acc;
}, {});
res = Object.values(res).map(arr => (arr.length <= 1 ? arr[0] : arr));
console.log(res);
.as-console {background-color:black !important; color:lime;}
.as-console-wrapper {max-height:100% !important; top:0;}
Ответ №8:
В Javascript для группировки объектов по свойству можно использовать метод Array.prototype.reduce() для объединения входных данных массива в набор результатов, сгруппированных по ключу (в данном случае ‘ship’). Используйте Object.values для извлечения значений из результирующего набора путем удаления ключей
var data = [
{ name: 'Malcolm Reynolds', ship: 'Serenity' },
{ name: 'Carmen Ibanez', ship: 'Rodger Young' },
{ name: 'Zander Barcalow', ship: 'Rodger Young' },
{ name: 'Hoban Washburne', ship: 'Serenity' },
{ name: 'James Kirk', ship: 'USS Enterprise' }];
var myNewObjArray = data.reduce((res,obj) =>{
const key = obj.ship;
if(!res[key]){
res[key] = [];
}
res[key].push(obj)
return res;
}, {});
console.log(Object.values(myNewObjArray));