Reputation: 160
I have an array of objects like this:
const data = [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" },
{ id: 8, type: { name: "B" }, condition: "broken" },
{ id: 9, type: { name: "C" }, condition: "broken" }
];
What i'm trying to do is to group those objects by type's key:value
in this case by name:value
, like this:
const data = [
{
by: {
type: { name: "A" }
},
chunks: [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" }
]
},
{
by: {
type: { name: "C" }
},
chunks: [
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 9, type: { name: "C" }, condition: "broken" }
]
},
{
by: {
type: { name: "B" }
},
chunks: [
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 8, type: { name: "B" }, condition: "broken" }
]
},
];
I've tried to use lodash and Array.prototype.reduce()
, my last attempt was using lodash, but i can't get the type as object.
_.chain(channels)
.groupBy("type.name")
.map((item, i) => {
return {
chunks: item,
by: i
};
})
.value();
Upvotes: 1
Views: 209
Reputation: 91
const data = [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" },
{ id: 8, type: { name: "B" }, condition: "broken" },
{ id: 9, type: { name: "C" }, condition: "broken" }
];
const data2 = {};
data.forEach(test => {
if (data2[test.type.name]) {
data2[test.type.name].chunks.push({
test
});
} else {
data2[test.type.name] = {
by: {
type: test.type
},
chunks: [
test
]
};
}
});
console.log(Object.values(data2));
Upvotes: 0
Reputation: 35242
You could use reduce
and Object.values
to group like this:
const data = [{"id":1,"type":{"name":"A"},"condition":"new"},{"id":2,"type":{"name":"C"},"condition":"broken"},{"id":3,"type":{"name":"C"},"condition":"brand new"},{"id":4,"type":{"name":"B"},"condition":"broken"},{"id":5,"type":{"name":"C"},"condition":"brand new"},{"id":6,"type":{"name":"A"},"condition":"new"},{"id":7,"type":{"name":"A"},"condition":"new"},{"id":8,"type":{"name":"B"},"condition":"broken"},{"id":9,"type":{"name":"C"},"condition":"broken"}];
const merged = data.reduce((acc, o) => {
const {type} = o;
acc[type.name] = acc[type.name] || { by: { type }, chunks:[] };
acc[type.name].chunks.push(o)
return acc;
},{})
const output = Object.values(merged)
console.log(output)
(Ignore snippet console
and check browser's console)
Upvotes: 1
Reputation: 37755
You can use reduce
Here the idea is
name
as key and checks if op
already has that particular key or not. if the key is already there we push the inp
to chunks
property of op. if not we add a new key with by
and chunks
with respective values.const data = [{ id: 1, type: { name: "A" }, condition: "new" },{ id: 2, type: { name: "C" }, condition: "broken" },{ id: 3, type: { name: "C" }, condition: "brand new" },{ id: 4, type: { name: "B" }, condition: "broken" },{ id: 5, type: { name: "C" }, condition: "brand new" },{ id: 6, type: { name: "A" }, condition: "new" },{ id: 7, type: { name: "A" }, condition: "new" },{ id: 8, type: { name: "B" }, condition: "broken" },{ id: 9, type: { name: "C" }, condition: "broken" }];
let op = data.reduce( (op,inp) => {
if( op[inp.type] ){
op[inp].chunks.push(inp)
} else {
op[inp] = {
by: {...inp.type},
chunks: [inp]
}
}
return op
},{})
console.log(Object.values(op))
Upvotes: 0
Reputation: 192016
Since you can't group by an object because two objects with the same keys and values are not the same object, you can use JSON.stringify()
to convert the object to a string, and group by it. Use Array.reduce()
to group the items by the stringified object. Convert to pairs using Object.entries()
, then map the values to an object, and extract the by
value using JSON.parse()
:
const groupByObj = (arr, key) => Object.entries(
arr.reduce((r, o) => {
const k = JSON.stringify({ [key]: o[key] });
r[k] = r[k] || [];
r[k].push(o);
return r;
}, {})
).map(([k, chunks]) => ({
by: JSON.parse(k),
chunks
}));
const data = [{"id":1,"type":{"name":"A"},"condition":"new"},{"id":2,"type":{"name":"C"},"condition":"broken"},{"id":3,"type":{"name":"C"},"condition":"brand new"},{"id":4,"type":{"name":"B"},"condition":"broken"},{"id":5,"type":{"name":"C"},"condition":"brand new"},{"id":6,"type":{"name":"A"},"condition":"new"},{"id":7,"type":{"name":"A"},"condition":"new"},{"id":8,"type":{"name":"B"},"condition":"broken"},{"id":9,"type":{"name":"C"},"condition":"broken"}];
const result = groupByObj(data, 'type');
console.log(result);
Upvotes: 1
Reputation: 281804
You just need to change the way you assing the value to by
in map. Assign like
return {
chunks: item,
by: { type: item[0].type}
};
const data = [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" },
{ id: 8, type: { name: "B" }, condition: "broken" },
{ id: 9, type: { name: "C" }, condition: "broken" }
];
console.log(_.chain(data)
.groupBy("type.name")
.map((item, i) => {
return {
by: { type: item[0].type},
chunks: item
};
})
.value())
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.min.js"></script>
Upvotes: 0
Reputation: 6749
Using lodash as you mentioned before we could do:
const data = [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" },
{ id: 8, type: { name: "B" }, condition: "broken" },
{ id: 9, type: { name: "C" }, condition: "broken" }
];
const groups = _.groupBy(data, (val) => val.type.name)
const formattedGroupd = Object.keys(groups).map(groupKey => {
return {
by: {type: { name: groupKey }},
chunks: groups[groupKey]
}
});
console.log(formattedGroupd)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>
Upvotes: 0
Reputation: 18513
Here you go:
const data = [
{ id: 1, type: { name: "A" }, condition: "new" },
{ id: 2, type: { name: "C" }, condition: "broken" },
{ id: 3, type: { name: "C" }, condition: "brand new" },
{ id: 4, type: { name: "B" }, condition: "broken" },
{ id: 5, type: { name: "C" }, condition: "brand new" },
{ id: 6, type: { name: "A" }, condition: "new" },
{ id: 7, type: { name: "A" }, condition: "new" },
{ id: 8, type: { name: "B" }, condition: "broken" },
{ id: 9, type: { name: "C" }, condition: "broken" }
];
let names = [];
data.forEach(x => {
if (names.indexOf(x.type.name)==-1) {
names.push(x.type.name);
}
});
let grouped = names.map(name => ({
by: { type: {name}},
chunks: data.filter(x => x.type.name==name)
}));
console.log(grouped);
Upvotes: 1
Reputation: 350365
You can use a Map
to collect the data by group, and then its values()
method will iterate the data as you want:
const data = [{ id: 1, type: { name: "A" }, condition: "new" },{ id: 2, type: { name: "C" }, condition: "broken" },{ id: 3, type: { name: "C" }, condition: "brand new" },{ id: 4, type: { name: "B" }, condition: "broken" },{ id: 5, type: { name: "C" }, condition: "brand new" },{ id: 6, type: { name: "A" }, condition: "new" },{ id: 7, type: { name: "A" }, condition: "new" },{ id: 8, type: { name: "B" }, condition: "broken" },{ id: 9, type: { name: "C" }, condition: "broken" }];
const map = new Map(data.map(o => [o.type.name, { by: { type: o.type.name }, chunks: [] }]));
data.forEach(o => map.get(o.type.name).chunks.push(o));
const result = [...map.values()];
console.log(result);
Upvotes: 1