Группировка элементов массива с использованием объекта
Мой массив выглядит примерно так:
myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
]
Я хочу преобразовать это в:
myArray = [
{group: "one", color: ["red", "green", "black"]}
{group: "two", color: ["blue"]}
]
Итак, в основном, группа за group
.
Я пытаюсь:
for (i in myArray){
var group = myArray[i].group;
//myArray.push(group, {???})
}
Я просто не знаю, как справиться с группировкой похожих групповых значений.
Ответы
Ответ 1
Во-первых, в JavaScript обычно не рекомендуется перебирать массивы с помощью for ... in
. См. Почему используется "для... в" с итерацией массива плохая идея? для деталей.
Итак, вы можете попробовать что-то вроде этого:
var groups = {};
for (var i = 0; i < myArray.length; i++) {
var groupName = myArray[i].group;
if (!groups[groupName]) {
groups[groupName] = [];
}
groups[groupName].push(myArray[i].color);
}
myArray = [];
for (var groupName in groups) {
myArray.push({group: groupName, color: groups[groupName]});
}
Использование промежуточного объекта groups
здесь помогает ускорить процесс, потому что он позволяет избежать циклов вложенности для поиска по массивам. Кроме того, поскольку groups
- это объект (а не массив), итерация по нему с использованием for ... in
является подходящей.
Добавление
FWIW, если вы хотите избежать дублирования записей цвета в результирующих массивах, вы можете добавить оператор if
над строкой groups[groupName].push(myArray[i].color);
для защиты от дубликатов. Используя jQuery, он будет выглядеть следующим образом:
if (!$.inArray(myArray[i].color, groups[groupName])) {
groups[groupName].push(myArray[i].color);
}
Без jQuery вы можете добавить функцию, которая делает то же самое, что и jQuery inArray
:
Array.prototype.contains = function(value) {
for (var i = 0; i < this.length; i++) {
if (this[i] === value)
return true;
}
return false;
}
а затем используйте его следующим образом:
if (!groups[groupName].contains(myArray[i].color)) {
groups[groupName].push(myArray[i].color);
}
Обратите внимание, что в любом случае вы собираетесь немного замедлить работу из-за всей дополнительной итерации, поэтому, если вам не нужно избегать дублирования записей цвета в массивах результатов, я бы рекомендовал избегать этого дополнительного кода. Там
Ответ 2
Начните с создания сопоставления имен групп со значениями.
Затем преобразуйте в желаемый формат.
var myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
];
var group_to_values = myArray.reduce(function (obj, item) {
obj[item.group] = obj[item.group] || [];
obj[item.group].push(item.color);
return obj;
}, {});
var groups = Object.keys(group_to_values).map(function (key) {
return {group: key, color: group_to_values[key]};
});
var pre = document.createElement("pre");
pre.innerHTML = "groups:\n\n" + JSON.stringify(groups, null, 4);
document.body.appendChild(pre);
Ответ 3
Использовать метод lodash groupby
Создает объект, состоящий из ключей, генерируемых из результатов запуска каждого элемента коллекции через итерацию. Порядок группируемых значений определяется порядком их возникновения в коллекции. Соответствующее значение каждой клавиши представляет собой массив элементов, ответственных за генерацию ключа. Итератор вызывается с одним аргументом: (значение).
Итак, с lodash вы можете получить то, что хотите, в одной строке. См. Ниже
let myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"},
]
let grouppedArray=_.groupBy(myArray,'group')
console.log(grouppedArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
Ответ 4
Один из вариантов:
var res = myArray.reduce(function(groups, currentValue) {
if ( groups.indexOf(currentValue.group) === -1 ) {
groups.push(currentValue.group);
}
return groups;
}, []).map(function(group) {
return {
group: group,
color: myArray.filter(function(_el) {
return _el.group === group;
}).map(function(_el) { return _el.color; })
}
});
http://jsfiddle.net/dvgwodxq/
Ответ 5
Помимо данных подходов с двухпроходным подходом, вы можете выбрать один цикл, нажав группу, если найдена новая группа.
var array = [{ group: "one", color: "red" }, { group: "two", color: "blue" }, { group: "one", color: "green" }, { group: "one", color: "black" }],
groups = Object.create(null),
grouped = [];
array.forEach(function (o) {
if (!groups[o.group]) {
groups[o.group] = [];
grouped.push({ group: o.group, color: groups[o.group] });
}
groups[o.group].push(o.color);
});
console.log(grouped);
.as-console-wrapper { max-height: 100% !important; top: 0; }
Ответ 6
myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
];
let group = myArray.map((item)=> item.group ).filter((item, i, ar) => ar.indexOf(item) === i).sort((a, b)=> a - b).map(item=>{
let new_list = myArray.filter(itm => itm.group == item).map(itm=>itm.color);
return {group:item,color:new_list}
});
console.log(group);
Ответ 7
Эта версия использует преимущества того, что ключи объектов уникальны. Мы обрабатываем исходный массив и собираем цвета по группе в новом объекте. Затем создайте новые объекты из этой группы → массив массивов цветов.
var myArray = [{
group: "one",
color: "red"
}, {
group: "two",
color: "blue"
}, {
group: "one",
color: "green"
}, {
group: "one",
color: "black"
}];
//new object with keys as group and
//color array as value
var newArray = {};
//iterate through each element of array
myArray.forEach(function(val) {
var curr = newArray[val.group]
//if array key doesnt exist, init with empty array
if (!curr) {
newArray[val.group] = [];
}
//append color to this key
newArray[val.group].push(val.color);
});
//remove elements from previous array
myArray.length = 0;
//replace elements with new objects made of
//key value pairs from our created object
for (var key in newArray) {
myArray.push({
'group': key,
'color': newArray[key]
});
}
Обратите внимание, что это не учитывает повторяющиеся цвета одной и той же группы, поэтому в одной группе может быть несколько одинаковых цветов в массиве.
Ответ 8
var array = [{
id: "123",
name: "aaaaaaaa"
}, {
id: "123",
name: "aaaaaaaa"
}, {
id: '456',
name: 'bbbbbbbbbb'
}, {
id: '789',
name: 'ccccccccc'
}, {
id: '789',
name: 'ccccccccc'
}, {
id: '098',
name: 'dddddddddddd'
}];
//if you want to group this array
group(array, key) {
console.log(array);
let finalArray = [];
array.forEach(function(element) {
var newArray = [];
array.forEach(function(element1) {
if (element[key] == element1[key]) {
newArray.push(element)
}
});
if (!(finalArray.some(arrVal => newArray[0][key] == arrVal[0][key]))) {
finalArray.push(newArray);
}
});
return finalArray
}
//and call this function
groupArray(arr, key) {
console.log(this.group(arr, key))
}
Ответ 9
Еще один вариант - использовать reduce()
и new Map()
для группировки массива. Используйте Spread syntax
для преобразования заданного объекта в массив.
var myArray = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}]
var result = [...myArray.reduce((c, {group,color}) => {
if (!c.has(group)) c.set(group, {group,color: []});
c.get(group).color.push(color);
return c;
}, new Map()).values()];
console.log(result);
Ответ 10
Вы можете сделать что-то вроде этого:
function convert(items) {
var result = [];
items.forEach(function (element) {
var existingElement = result.filter(function (item) {
return item.group === element.group;
})[0];
if (existingElement) {
existingElement.color.push(element.color);
} else {
element.color = [element.color];
result.push(element);
}
});
return result;
}
Ответ 11
Использование массива reduce
и findIndex
методы, это может быть достигнуто.
var myArray = [{
group: "one",
color: "red"
}, {
group: "two",
color: "blue"
}, {
group: "one",
color: "green"
}, {
group: "one",
color: "black"
}];
var transformedArray = myArray.reduce((acc, arr) => {
var index = acc.findIndex(function(element) {
return element.group === arr.group;
});
if (index === -1) {
return acc.push({
group: arr.group,
color: [arr.color]
});
}
acc[index].color.push(arr.color);
return acc;
}, []);
console.log(transformedArray);
Ответ 12
Вы можете расширить функциональность массива с помощью следующего:
Array.prototype.groupBy = function(prop) {
var result = this.reduce(function (groups, item) {
const val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
return Object.keys(result).map(function(key) {
return result[key];
});
};
Пример использования:
/* re-usable function */
Array.prototype.groupBy = function(prop) {
var result = this.reduce(function (groups, item) {
const val = item[prop];
groups[val] = groups[val] || [];
groups[val].push(item);
return groups;
}, {});
return Object.keys(result).map(function(key) {
return result[key];
});
};
var myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
]
console.log(myArray.groupBy('group'));
Ответ 13
Попробуйте (h = {})
myArray.forEach(x=> h[x.group]= (h[x.group]||[]).concat(x.color) );
myArray = Object.keys(h).map(k=> ({group:k, color:h[k]}))
let myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"},
];
let h={};
myArray.forEach(x=> h[x.group]= (h[x.group]||[]).concat(x.color) );
myArray = Object.keys(h).map(k=> ({group:k, color:h[k]}))
console.log(myArray);