My collection contains the following (array of objects):
[
{
id: 'id-1',
uniqueName: 'operation-level-1',
operations: [
{
name: 'operaion-1',
label: 'operation-1-label'
},
{
name: 'operaion-2',
label: 'operation-2-label'
}
]
},
{
id: 'id-2',
uniqueName: 'operation-level-2'
operations: [
{
name: 'operaion-1',
label: 'operation-1-label'
},
{
name: 'operaion-3',
label: 'operation-3-label'
}
]
}
]
I wanted to get an array of unique operation name and label as shown below
const result = [
{
name: 'operaion-1',
label: 'operation-1-label'
},
{
name: 'operaion-2',
label: 'operation-2-label'
},
{
name: 'operaion-3',
label: 'operation-3-label'
}
]
Can someone suggest the best way to achieve this, please?
This can be easily done without lodash. You can first flat the data then map it as a key value pair and then make use of Map to remove the duplicate entries:
var data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];
var result = [...new Map(data.flatMap(({operations})=>operations).map(k=>([k.name, k]))).values()];
console.log(result);
Or if you do not want to use Map then use filter method:
var data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];
var result = data.flatMap(({operations})=>operations).filter((val,i,self)=>self.findIndex(j=>j.name==val.name && j.label==val.label)==i);
console.log(result);
Use _.flatMap() to get a flattened array of operations, and then use _.uniqBy() to get only items with unique name:
const data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];
const result = _.uniqBy(
_.flatMap(data, 'operations'),
'name'
);
console.log(result);
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.15/lodash.js"></script>
With lodash/fp you can generate a function using _.flow() that flattens operations, and then get the unique values by name:
const fn = _.flow(
_.flatMap('operations'),
_.uniqBy('name')
)
const data=[{ id: 'id-1', uniqueName: 'operation-level-1', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-2', label: 'operation-2-label' } ] }, { id: 'id-2', uniqueName: 'operation-level-2', operations: [ { name: 'operaion-1', label: 'operation-1-label' }, { name: 'operaion-3', label: 'operation-3-label' } ] }];
const result = fn(data);
console.log(result);
<script src='https://cdn.jsdelivr.net/g/lodash#4(lodash.min.js+lodash.fp.min.js)'></script>
There is no need for loadash, a simple Map object, will allow you to suppress the duplicates.
const arr = [{
id: 'id-1',
uniqueName: 'operation-level-1',
operations: [{
name: 'operaion-1',
label: 'operation-1-label'
},
{
name: 'operaion-2',
label: 'operation-2-label'
}
]
},
{
id: 'id-2',
uniqueName: 'operation-level-2',
operations: [{
name: 'operaion-1',
label: 'operation-1-label'
},
{
name: 'operaion-3',
label: 'operation-3-label'
}
]
}
];
// Go thought the arr and add all the name/label into the map
// Then use Array.from to reformate the Map into the wanted format
const uniqueArr = Array.from(arr.reduce((tmp, {
operations,
}) => {
operations.forEach(({
name,
label,
}) => {
tmp.set(name, label);
});
return tmp;
}, new Map())).map(([name, label]) => ({
name,
label,
}));
console.log(uniqueArr);
Related
I'm trying to find an element on a multidimentionnal array usin JAVASCRIPT function, but I get error
This is my array's data:
export const datas = [
{
id: 1,
firstName: 'John',
tables: [
{ ID: 11, title: 'Lorem' },
{ ID: 12, title: 'Ipsum' },
],
},
{
id: 2,
firstName: 'Doe',
tables: [
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
{ ID: 23, title: 'Korem' },
],
},
{
id: 3,
firstName: 'Brad',
tables: [
{
ID: 30,
title: 'Mern',
nodes: [{ name: 'Name4' }, { name: 'Name5' }, { name: 'Name6' }],
},
{
ID: 31,
title: 'Full',
nodes: [{ name: 'Name7' }, { name: 'Name8' }, { name: 'Name9' }],
},
],
},
];
I've tried a reccursive function but it's not work, this is my code :
export const findById = (arr, id) => {
for (let o of arr) {
if (o.tables.length > 0) {
let a = findById(o.tables.nodes, 'id');
console.log(a);
}
}
};
I want to print the Object with ID 22, the problem is that I don't have the same structure in each dimension, and it still confuse me..
My Input : 22
My output :
{
ID: 22,
title: 'Arke',
nodes: [{ name: 'Name1' }, { name: 'Name2' }, { name: 'Name3' }],
},
Have you an idea how to edit my function to get my input's response ?
Your recursive function wasn't too far off, you need to check if the item as a tables first before recursively calling it again. And then finally just check the ID in the loop.
eg..
const datas=[{id:1,firstName:"John",tables:[{ID:11,title:"Lorem"},{ID:12,title:"Ipsum"}]},{id:2,firstName:"Doe",tables:[{ID:22,title:"Arke",nodes:[{name:"Name1"},{name:"Name2"},{name:"Name3"}]},{ID:23,title:"Korem"}]},{id:3,firstName:"Brad",tables:[{ID:30,title:"Mern",nodes:[{name:"Name4"},{name:"Name5"},{name:"Name6"}]},{ID:31,title:"Full",nodes:[{name:"Name7"},{name:"Name8"},{name:"Name9"}]}]}];
function findById(arr, ID) {
for (const a of arr) {
if (a.tables) {
const r = findById(a.tables, ID);
if (r) return r;
}
if (a.ID === ID) return a;
}
}
console.log(findById(datas, 22));
if you just need the nested data you can use flatMap and find
const findById = (arr, id) =>
arr
.flatMap(d => d.tables)
.find(t => t.ID === id)
const datas = [{
id: 1,
firstName: 'John',
tables: [{
ID: 11,
title: 'Lorem'
},
{
ID: 12,
title: 'Ipsum'
},
],
},
{
id: 2,
firstName: 'Doe',
tables: [{
ID: 22,
title: 'Arke',
nodes: [{
name: 'Name1'
}, {
name: 'Name2'
}, {
name: 'Name3'
}],
},
{
ID: 23,
title: 'Korem'
},
],
},
{
id: 3,
firstName: 'Brad',
tables: [{
ID: 30,
title: 'Mern',
nodes: [{
name: 'Name4'
}, {
name: 'Name5'
}, {
name: 'Name6'
}],
},
{
ID: 31,
title: 'Full',
nodes: [{
name: 'Name7'
}, {
name: 'Name8'
}, {
name: 'Name9'
}],
},
],
},
];
console.log(findById(datas, 22))
js has amazing array options https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array
the ones which will help you most are probably:
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/filter
https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flatMap
here are some examples
// get the base with id 22
const baseWith22ID = datas.filter(f => f.tables.filter(s => s.id = 22))
// (i guess you want this one) get all elements with id 22
const onlyElementsWith22ID = datas.flatMap(f => f.tables.filter(s => s.id = 22))
I'm trying to figure out how you would return the matching value in this example below.
const selected = [{
name: 'Colour group',
value: 'White',
}, {
name: 'Style',
value: 'Cream',
}];
const overrides = [{
facets: [{
name: "Colour group",
values: ["White"]
}]
}, {
facets: [{
test: 'name',
name: "Colour group",
values: ["White", "Cream"],
}]
}, {
facets: [{
test: 'name',
name: "Colour group",
values: ["White", "test"],
}]
}, {
facets: [{
name: "Colour group",
values: ["White"]
}, {
name: "Style",
values: ["Cream"]
}]
}, {
facets: [{
name: "Colour group",
values: ["White"]
}, {
name: "Range",
values: ["Cream"]
}]
}];
So if my selected facets were Colour group and Style I'd then need to match it to the override that also has Colour group and Style and return. Ignoring the one that has Colour group and Range.
I have a JSfiddle with my current progress:
https://jsfiddle.net/61wvubmz/53/
Ideally this will then check if the values are the same and return the override object.
The expected return would be
{
facets: [{
name: "Colour group",
values: ["White"]
}, {
name: "Style",
values: ["Cream"]
}]
}
from the override array
const lookfor = selected.map((val) => val.name);
const facets = overrides.filter((o) => {
let compatible = true;
lookfor.forEach((lf) => {
if(!o.facets.find((of) => of.name === lf)){
compatible = false
}
})
return compatible
})
console.log(facets);
https://jsfiddle.net/r5nd40z9/4/
const selected = [{
name: 'Colour group',
value: 'White',
},
{
name: 'Style',
value: 'Cream',
}
];
const overrides = [{
facets: [{
name: "Colour group",
values: ["White"]
}]
},
{
facets: [{
test: 'name',
name: "Colour group",
values: ["White", "Cream"],
}]
}, {
facets: [{
test: 'name',
name: "Colour group",
values: ["White", "test"],
}]
}, {
facets: [{
name: "Colour group",
values: ["White"]
}, {
name: "Style",
values: ["Cream"]
}]
}, {
facets: [{
name: "Colour group",
values: ["White"]
}, {
name: "Range",
values: ["Cream"]
}]
}];
let result = {}
let output = overrides.filter(o1 => !selected.some(s1 => {
let r1, r2;
r1 = o1.facets[0].name === s1.name;
(o1.facets.length > 1) ? r2 = o1.facets[1].name === s1.name : ' ';
r2 ? result = o1 : ' '
}));
console.log(result)
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 3 years ago.
Improve this question
I have an object :
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
How can I add to each object in groups id with the same value as in name prop to get this:
const obj2 = {
app: {
groups: [{ name: 'name', values: 'values', id: 'name' }, { name: 'name1', values: 'values1', id: 'name1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values', id: 'name2' }, { name: 'name7', values: 'values4', id: 'name7' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5', id: 'name5' }, { name: 'name4', values: 'values4', id: 'name4' }]
}
};
Mutable version: If you can modify your input object, use Array.forEach() twice:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
Object.keys(obj).forEach(key => {
obj[key].groups.forEach(x => x.id = x.name);
});
console.log(obj);
Immutable version: If you don't want to modify your input object, use Array.reduce() and the spread operator to copy properties from the inner objects:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
const result = Object.entries(obj).reduce((acc, [key, val]) => {
acc[key] = { groups: val.groups.map(x => ({ ...x, id: x.name })) };
return acc;
}, {});
console.log(result);
In both cases, you'll need to iterate over the keys using Object.keys() or directly over the entries with Object.entries().
Loop through your object and then loop through the array in your inner object:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
for (app in obj) {
obj[app].groups.forEach(innerObj => {
innerObj.id = innerObj.name;
});
}
console.log(obj);
Iterate over Object.keys and use map like so:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
function addIdProp(object) {
let result = object;
Object.keys(result).forEach(key => {
result[key].groups = result[key].groups.map(({ name, values }) => { return { name, values, id: name}});
});
return result;
}
const obj2 = addIdProp(obj);
console.log(obj2);
.as-console-wrapper { max-height: 100% !important; top: 0 }
ES5 syntax:
var obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
function addIdProp(object) {
var result = object;
Object.keys(result).forEach(function(key) {
result[key].groups = result[key].groups.map(function({ name, values }) { return { name: name, values: values, id: name}});
});
return result;
}
var obj2 = addIdProp(obj);
console.log(obj2);
.as-console-wrapper { max-height: 100% !important; top: 0 }
What about with this?
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
for (let k in obj) {
if (obj.hasOwnProperty(k)) {
obj[k].groups = obj[k].groups.map((g) => {
return { ...g, id: g.name}
})
}
}
console.log(obj);
Loop through the object properties and add their group array a id prop assigning the relevant name with two nested forEaches as follows:
const obj = {
app: {
groups: [{
name: 'name',
values: 'values'
}, {
name: 'name1',
values: 'values1'
}]
},
app2: {
groups: [{
name: 'name2',
values: 'values'
}, {
name: 'name2',
values: 'values4'
}]
},
app3: {
groups: [{
name: 'name5',
values: 'values5'
}, {
name: 'name4',
values: 'values4'
}]
}
};
Object.keys(obj).forEach(e => obj[e].groups.forEach(el => el.id = el.name));
console.log(JSON.stringify(obj))
Note that it does this implementation does not create a new object, instead modifies the initial one. Your use case may welcome or discourage it.
You can try with for..in and forEach
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
for (let item in obj) {
obj[item].groups.forEach(o => o.id = o.name)
}
console.log(obj)
One solution that is purely function, immutable, and independent of scope/closure would be to reduce the [Object.entries()][1] of the obj into a new obj2 result like so:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1' }]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
/* Reduce entries into a new object */
const obj2 = Object.entries(obj).reduce((newObject, [key, value]) => {
/* For each value of new object array of, map group items to include id : name property */
newObject[ key ] = { groups : value.groups.map(item => ({ ...item, id : item.name })) }
return newObject
}, {})
console.log(obj2)
You have to loop through the object first and then map inside the groups array like that:
const obj = {
app: {
groups: [{ name: 'name', values: 'values' }, { name: 'name1', values: 'values1'}]
},
app2: {
groups: [{ name: 'name2', values: 'values' }, { name: 'name2', values: 'values4' }]
},
app3: {
groups: [{ name: 'name5', values: 'values5' }, { name: 'name4', values: 'values4' }]
}
};
var newObj = {...obj};
for(var key in newObj){
newObj[key] = newObj[key].groups.map(item => ({...item, id: item.name}));
}
console.log(newObj); // here is your new object with id's
You can do:
const obj = {app: {groups: [{name: 'name',values: 'values'}, {name: 'name1',values: 'values1'}]},app2: {groups: [{name: 'name2',values: 'values'}, {name: 'name2',values: 'values4'}]},app3: {groups: [{name: 'name5',values: 'values5'}, {name: 'name4',values: 'values4'}]}};
const obj2 = Object.keys(obj).map(k => ({
[k]: {
groups: obj[k].groups.map(o => {
o.id = o.name;
return o;
})
}
}));
console.log(obj2);
.as-console-wrapper { max-height: 100% !important; top: 0; }
I have such an object
data: {
dataFirst: {
Food: [ {id: 536131, name: "option1", }]
},
dataSecond: {
Autos: [{id: 678, name: 'option1'}],
Houses: [
{id: 6876, name: "option1"},
{id: 6876, name: "Placed App"},
],
Phones: [
{id: 672, name: "option1"},
{id: 97249, name: "Placed},
],
Food: [
{id: 772, name: "option1"},
{id: 6777, name: "Placed},
],
}
}
The problem is, that I may have same data in dataFirst and dataSecond, for examle 'Food', I have 2 array objects that contains different data but I need to make it one object 'Food' with the data from 2 of them, from the dataFirst 'Food' and dataSecond 'Food'. I had such a code:
export const parser = ({ data }) => {
const result = Object.values(data).reduce((prev, topicsGroup) => {
Object.assign(prev, topicsGroup);
return prev;
}, {});
return result;
}
but this code doesn't unite 2 'Food' objects but returns data only from the dataFirst 'Food' object wihout second one.
You can iterate through all values of your main data object with Object.values(data) and combine them with reduce by concatenating arrays corresponding to common keys:
let data = {
dataFirst: {
Food: [{
id: 536131,
name: "option1",
}]
},
dataSecond: {
Autos: [{
topicId: 678,
name: 'option1'
}],
Houses: [{
topicId: 6876,
name: "option1"
},
{
topicId: 6876,
topicName: "Placed App"
},
],
Phones: [{
topicId: 672,
name: "option1"
},
{
topicId: 97249,
name: "Placed"
},
],
Food: [{
topicId: 772,
name: "option1"
},
{
topicId: 6777,
name: "Placed"
},
],
}
};
let res = Object.values(data).reduce((acc, curr) => {
Object.entries(curr).forEach(([k, v]) => {
if (k in acc) acc[k] = acc[k].concat(v);
else acc[k] = v;
});
return acc;
}, {});
console.log(res);
How do I return a set of documents that has sub-arrays that matches common values. To better explain, consider the following data:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
The task is,
Get all the Categories with all the products containing a specific color code:
For example,
For ColorCode = 6,
Result should be:
[
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[5,6,9,]
}
]
},
{
Category: 3,
Products: [
{
Name: 'OPQ',
ColorCode:[3,4,5,6,9,10]
},
{
Name: 'RST',
ColorCode:[2,3,5,6,9,10]
}
]
}]
For ColorCode = 4,
Result should be:
[
{
Category: 1,
Products: [
{
Name: 'ABC',
ColorCode:[1,2,3,4,5]
},
{
Name: 'DEF',
ColorCode:[1,2,3,4,5,6]
},
{
Name: 'GHI',
ColorCode:[1,2,3,4,6,7]
}
]
},
{
Category: 2,
Products: [
{
Name: 'JKL',
ColorCode:[4,6,7,]
},
{
Name: 'MNO',
ColorCode:[4,5,6,9,]
}
]
}]
For ColorCode = 7,
Result should be an empty array:
[]
Thanks in advance.
You're looking for Array.prototype.filter.
// filter out categories that don't contain color code 4
categories.filter(function(category) {
return category.products.filter(containsColor(4)) > 0;
});
function containsColor(colorCode) {
return function(product) {
return product.ColorCode.indexOf(colorCode) >= 0;
};
}