admin管理员组文章数量:1221774
I'm looking for an efficient way to return unique values in objects inside an array. For example the next object:
{
"products": [{
"id": 1,
"category": "test1",
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"category": "test2",
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"category": "test1",
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"category": "test2",
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
}
What I want to return is the following:
{"option": [ "A", "B", "C" ] },{"type": ["A", "B", "C"] }
So I want for each item inside the tags object a new object. After that, I want an array with all unique values over all the products.
I do somewhat the same with another function:
Array.from(new Set(data.map(p => { return p.category; })))
This is a level higher which makes it easier. Can someone push me in the right direction?
I'm looking for an efficient way to return unique values in objects inside an array. For example the next object:
{
"products": [{
"id": 1,
"category": "test1",
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"category": "test2",
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"category": "test1",
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"category": "test2",
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
}
What I want to return is the following:
{"option": [ "A", "B", "C" ] },{"type": ["A", "B", "C"] }
So I want for each item inside the tags object a new object. After that, I want an array with all unique values over all the products.
I do somewhat the same with another function:
Array.from(new Set(data.map(p => { return p.category; })))
This is a level higher which makes it easier. Can someone push me in the right direction?
Share Improve this question edited Mar 4, 2020 at 8:52 Fred 3,4214 gold badges37 silver badges58 bronze badges asked Mar 4, 2020 at 8:43 FrankFrank 12310 bronze badges 4 |5 Answers
Reset to default 7Make two sets instead, one for the option
s found so far, and one for the type
s found so far:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
const options = new Set();
const types = new Set();
for (const { tags: { option=[], type=[] } } of obj.products) {
for (const o of option) options.add(o);
for (const t of type) types.add(t);
}
console.log({
option: [...options],
type: [...types]
});
An alternative, for arbitrary keys:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
const setObj = {};
for (const { tags } of obj.products) {
for (const [key, arr] of Object.entries(tags)) {
if (!setObj[key]) setObj[key] = new Set();
for (const item of arr) setObj[key].add(item);
}
}
const output = Object.fromEntries(
Object.entries(setObj).map(([key, set]) => [key, [...set]])
);
console.log(output);
You could take a Map
for wanted keys and collect the values in a Set
.
function getUnique(array, keys) {
var maps = new Map(keys.map(k => [k, new Set]));
array.forEach(({ tags }) =>
keys.forEach(k => (tags[k] || []).forEach(v => maps.get(k).add(v))));
return Array.from(maps, ([k, s]) => ({ [k]: Array.from(s) }));
}
var data = { products: [{ id: 1, tags: { option: ["A", "B"] } }, { id: 2, tags: { option: ["B"], type: ["A", "B", "C"] } }, { id: 3, tags: { type: ["A"] } }, { id: 4, tags: { option: ["B", "C"], type: ["A", "C"] } }] },
unique = getUnique(data.products, ['option', 'type']);
console.log(unique);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can create an object with two required keys and then set then to empty arrays. Then loop through the array and add the new elements to that array and after that remove the duplicates
const arr = [{
"id": 1,
"tags": {
"option": ["A", "B"]
}}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
} }, {
"id": 3,
"tags": {
"type": ["A"]
}}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}}]
const object = {option:[] , type: []}
arr.forEach(({tags}) => {
for(let prop in object){
if(tags[prop]){
object[prop] = [...new Set([...object[prop], ...tags[prop]])]
}
}
})
console.log(object)
You can use Array.prototype.reduce() to make the result variable { option: [], type: [] }
- then iterate over desired properties
['option', 'type']
with Array.prototype.forEach() - finally get the unique values array with the Set object after Array.prototype.concat() the arrays for each products
Code:
const data = {"products": [{"id": 1,"tags": {"option": ["A", "B"]}}, {"id": 2,"tags": {"option": ["B"],"type": ["A", "B", "C"]}}, {"id": 3,"tags": {"type": ["A"]}}, {"id": 4,"tags": {"option": ["B", "C"],"type": ["A", "C"]}}]}
const result = data.products.reduce((a, { tags }) => {
['option', 'type'].forEach(prop => {
a[prop] = [...new Set(a[prop].concat(tags[prop] || []))]
})
return a
}, { option: [], type: [] })
console.log(result)
A simple yet efficient solution is:
const optionSet = new Set();
const typeSet = new Set();
data.products.forEach( pr =>{
if(pr.tags.option){
pr.tags.option.forEach( op =>{
optionSet.add(op)
})
}
if(pr.tags.type){
pr.tags.type.forEach( tp =>{
typeSet.add(tp);
})
}
})
Performance comparison:
const obj = {
"products": [{
"id": 1,
"tags": {
"option": ["A", "B"]
}
}, {
"id": 2,
"tags": {
"option": ["B"],
"type": ["A", "B", "C"]
}
}, {
"id": 3,
"tags": {
"type": ["A"]
}
}, {
"id": 4,
"tags": {
"option": ["B", "C"],
"type": ["A", "C"]
}
}]
};
//efficient solution
let t0 = performance.now();
const optionSet = new Set();
const typeSet = new Set();
obj.products.forEach( pr =>{
if(pr.tags.option){
pr.tags.option.forEach( op =>{
optionSet.add(op)
})
}
if(pr.tags.type){
pr.tags.type.forEach( tp =>{
typeSet.add(tp);
})
}
})
let s1Result = {
options: [...optionSet],
types: [...typeSet]
}
let t1 = performance.now();
let s1Runtime = t1-t0
console.log("efficient took: ",s1Runtime);
//accepted answer
let t2 = performance.now();
const setObj = {};
for (const { tags } of obj.products) {
for (const [key, arr] of Object.entries(tags)) {
if (!setObj[key]) setObj[key] = new Set();
for (const item of arr) setObj[key].add(item);
}
}
const s2Result = Object.fromEntries(
Object.entries(setObj).map(([key, set]) => [key, [...set]])
);
let t3 = performance.now();
let s2Runtime = t3-t2
console.log("current solution took: ",s2Runtime);
//runtime comparison
console.log("efficient solution is "+ ((s1Runtime)/(s2Runtime)).toFixed(2)*100 + " % faster current solution");
console.log("efficient solution result:", s1Result);
console.log("current solution result:", s2Result);
本文标签: javascriptLoop over objects inside a list and return unique valuesStack Overflow
版权声明:本文标题:javascript - Loop over objects inside a list and return unique values - Stack Overflow 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.betaflare.com/web/1739373687a2160377.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
p.category
? There is no mention of it in your sample data. – Terry Commented Mar 4, 2020 at 8:48data.json
file, it's not an object. – Cerbrus Commented Mar 4, 2020 at 8:48