My array is something like this:
myArray = [
{group: "one", color: "red"}
{group: "two", color: "blue"}
{group: "one", color: "green"}
{group: "one", color: "black"}
]
I want to convert this into:
myArray = [
{group: "one", color: ["red", "green", "black"]}
{group: "two", color: ["blue"]}
]
So, basically, group by group
.
I'm trying:
for (i in myArray){
var group = myArray[i].group;
//myArray.push(group, {???})
}
I just don't know how to handle the grouping of similar group values.
答案 0 :(得分:68)
首先创建组名到值的映射。 然后转换为您想要的格式。
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);
答案 1 :(得分:26)
First, in JavaScript it's generally not a good idea to iterate over arrays using for ... in
. See Why is using "for...in" with array iteration a bad idea? for details.
So you might try something like this:
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]});
}
Using the intermediary groups
object here helps speed things up because it allows you to avoid nesting loops to search through the arrays. Also, because groups
is an object (rather than an array) iterating over it using for ... in
is appropriate.
Addendum
FWIW, if you want to avoid duplicate color entries in the resulting arrays you could add an if
statement above the line groups[groupName].push(myArray[i].color);
to guard against duplicates. Using jQuery it would look like this;
if (!$.inArray(myArray[i].color, groups[groupName])) {
groups[groupName].push(myArray[i].color);
}
Without jQuery you may want to add a function that does the same thing as jQuery's inArray
:
Array.prototype.contains = function(value) {
for (var i = 0; i < this.length; i++) {
if (this[i] === value)
return true;
}
return false;
}
and then use it like this:
if (!groups[groupName].contains(myArray[i].color)) {
groups[groupName].push(myArray[i].color);
}
Note that in either case you are going to slow things down a bit due to all the extra iteration, so if you don't need to avoid duplicate color entries in the result arrays I would recommend avoiding this extra code. There
答案 2 :(得分:7)
使用lodash&#39; groupby
方法
创建一个对象,该对象由通过iteratee运行集合的每个元素的结果生成的键组成。分组值的顺序由它们在集合中出现的顺序确定。每个键的对应值是负责生成密钥的元素数组。使用一个参数调用iteratee :( value)。
因此,使用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)
&#13;
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.4/lodash.min.js"></script>
&#13;
答案 3 :(得分:5)
One option is:
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; })
}
});
答案 4 :(得分:4)
使用ES6,可以将dataTask(...){...}.resume()
与Map
作为累加器,然后使用Array.from()
及其映射功能将每个分组的map-entry映射到对象:
.reduce()
如果您的对象中除了const arr = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}];
const res = Array.from(arr.reduce((m, {group, color}) =>
m.set(group, [...(m.get(group) || []), color]), new Map
), ([group, color]) => ({group, color})
);
console.log(res);
和group
之外还具有其他属性,则可以通过将分组对象设置为地图的值来采用更通用的方法,如下所示:
color
如果可以支持optional chaining和nullish coalescing operator (??),则可以将上述方法简化为以下内容:
const arr = [{"group":"one","color":"red"},{"group":"two","color":"blue"},{"group":"one","color":"green"},{"group":"one","color":"black"}];
const groupAndMerge = (arr, groupBy, mergeInto) =>
Array.from(arr.reduce((m, o) => {
const curr = m.get(o[groupBy]);
return m.set(o[groupBy], {...o, [mergeInto]: [...(curr && curr[mergeInto] || []), o[mergeInto]]});
}, new Map).values());
console.log(groupAndMerge(arr, 'group', 'color'));
答案 5 :(得分:3)
除了使用两遍方法的给定方法之外,如果找到新组,则可以通过推送组来采用单循环方法。
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);
&#13;
.as-console-wrapper { max-height: 100% !important; top: 0; }
&#13;
答案 6 :(得分:3)
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 :(得分:2)
This version takes advantage that object keys are unique. We process the original array and collect the colors by group in a new object. Then create new objects from that group -> color array map.
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]
});
}
Please note that this does not take into account duplicate colors of the same group, so it is possible to have multiple of the same color in the array for a single group.
答案 8 :(得分:1)
另一个选择是使用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);
答案 9 :(得分:1)
此仓库提供lodash解决方案和本机Js中的替代方案,您可以找到如何实现groupby。 https://developer.mozilla.org/en-US/docs/Web/CSS/animation-timing-function#Step_examples
答案 10 :(得分:1)
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))
}
答案 11 :(得分:0)
使用数组的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);
&#13;
通过使用reduce
函数,数组是迭代器,新值存储在acc (accumulating)
参数中。要检查给定group
的对象是否已存在,我们可以使用findIndex
函数。
如果findIndex()
返回-1,则该值不存在,因此请在acc
参数中添加该数组。
如果findIndex()
返回索引,则使用index
值更新arr
。
答案 12 :(得分:0)
您可以使用下一个扩展数组功能:
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 :(得分:0)
我使用减速器的方法:
myArray = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
]
console.log(myArray.reduce( (acc, curr) => {
const itemExists = acc.find(item => curr.group === item.group)
if(itemExists){
itemExists.color = [...itemExists.color, curr.color]
}else{
acc.push({group: curr.group, color: [curr.color]})
}
return acc;
}, []))
答案 14 :(得分:0)
如果您不想重复使用颜色值,这将为您提供独特的颜色
var arr = [
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "red"},
{group: "two", color: "blue"},
{group: "one", color: "green"},
{group: "one", color: "black"}
]
var arra = [...new Set(arr.map(x => x.group))]
let reformattedArray = arra.map(obj => {
let rObj = {}
rObj['color'] = [...new Set(arr.map(x => x.group == obj ? x.color:false ))]
.filter(x => x != false)
rObj['group'] = obj
return rObj
})
console.log(reformattedArray)
答案 15 :(得分:0)
You can do something like this:
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;
}
答案 16 :(得分:0)
我喜欢使用 Map
构造函数回调来创建组(映射键)。第二步是填充该地图的值,最后以所需的输出格式提取地图数据:
let myArray = [{group: "one", color: "red"},{group: "two", color: "blue"},
{group: "one", color: "green"},{group: "one", color: "black"}];
let map = new Map(myArray.map(({group}) => [group, { group, color: [] }]));
for (let {group, color} of myArray) map.get(group).color.push(color);
let result = [...map.values()];
console.log(result);
答案 17 :(得分:-1)
尝试(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);