Extract objects from nested array of objects - javascript

I have the following data that is an array of nested objects:
"categories": [
{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
]
I want to extract unique years in a separate array (desired output):
[
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" },
]
When I map out the years, I'm getting an array of arrays, how should I extract the unique objects for years?
let years = categories.map( (c) => { return c.years })

You can use a Map to filter duplicate years from the array of values using id as the key, and reduce() on both categories and years using the map as the accumulator:
const categories = [{
"id": 1,
"name": "Category 1",
"years": [
{ "id": 1, "name": "1" },
{ "id": 2, "name": "2" }
]
},
{
"id": 2,
"name": "Category 2",
"years": [
{ "id": 2, "name": "2" },
{ "id": 3, "name": "3" }
]
}
];
const years = categories.reduce(
(map, category) => category.years.reduce(
(map, year) => map.set(year.id, year),
map
),
new Map()
);
console.log([...years.values()]);

You can use reduce and Map
let data = [{"id": 1,"name": "Category 1","years": [{ "id": 1, "name": "1" },{ "id": 2, "name": "2" }]},{"id": 2,"name": "Category 2","years": [{ "id": 2, "name": "2" },{ "id": 3, "name": "3" }]}]
let final = data.reduce((op,{years}) => {
years.forEach(({id, name}) => {
let key = id + '-' + name
op.set(key, op.get(key) || {id, name})
})
return op
},new Map())
console.log([...final.values()])

Related

Return an object if the value exists from an inside array [duplicate]

This question already has answers here:
JS (ES6): Filter array based on nested array attributes
(7 answers)
Filtering array of objects with arrays based on nested value
(8 answers)
Closed 10 days ago.
I need to return the object which hobbies is reading, below is my sample scenario
[
{
"id": 1,
"name": "john",
"hobbies": [
{
"id": 1,
"name": "playing"
}
]
},
{
"id": 3,
"name": "peter",
"hobbies": [
{
"id": 3,
"name": "reading"
}
]
}
]
// Expected Output:
[
{
"id": 3,
"name": "peter",
"hobbies": [
{
"id": 3,
"name": "reading"
}
]
}
]
I use filter() and find() method however i couldn't loop it inside hobbies array
Use Array#filter in conjunction with Array#some.
let arr = [ { "id": 1, "name": "john", "hobbies": [ { "id": 1, "name": "playing" } ] }, { "id": 2, "name": "mary", "hobbies": [ { "id": 2, "name": "cleaning" } ] }, { "id": 3, "name": "peter", "hobbies": [ { "id": 3, "name": "reading" } ] } ];
let res = arr.filter(x => x.hobbies.some(h => h.name === 'reading'));
console.log(res);
Use Array.prototype.filter method to filter the outer array and Array.prototype.some method to check if an object in the inner hobbies array has a name property of "reading"
let people = [ { "id": 1, "name": "john", "hobbies": [ { "id": 1, "name": "playing" } ] }, { "id": 2, "name": "mary", "hobbies": [ { "id": 2, "name": "cleaning" } ] }, { "id": 3, "name": "peter", "hobbies": [ { "id": 3, "name": "reading" } ] } ];
let readingPerson = people.filter(person =>
person.hobbies.some(hobby => hobby.name === "reading")
)[0];
console.log(readingPerson);

React - Filter Multidimensional array with another array

I want to return only matches results.
My array:
products: [
{
"id": 1,
"name": "Product 1",
"concepts": [
{
"id": 10,
"name": "Blabla"
},
{
"id": 15,
"name": "Zlazla"
}
]
},
{
"id": 2,
"name": "Product 2",
"concepts": [
{
"id": 14,
"name": "Gulagula"
},
{
"id": 15,
"name": "Zlazla"
}
]
}
]
I want to filter products which only have one of the concepts below.
concepts array:
['14', '15']
Couldn't solve this in an easy way.
You can try this way:
var products= [
{
"id": 1,
"name": "Product 1",
"concepts": [
{
"id": 10,
"name": "Blabla"
},
{
"id": 15,
"name": "Zlazla"
}
]
},
{
"id": 2,
"name": "Product 2",
"concepts": [
{
"id": 14,
"name": "Gulagula"
},
{
"id": 15,
"name": "Zlazla"
}
]
}
]
var products = products.filter((product) => product.concepts = product.concepts.filter( (x) => x.id == 14 || x.id == 15));
console.log(products);

Filtering an array based on multiple arrays inputs

I have three arrays.
1. Existing viewers array - existingViewers
New viewers array - newViewers
Permitted Viewers array - permittedViewers
permittedViewers is used for rendering the drop-down. And I wish to filter the newViewers and existingViewers entries from the permittedViewers.
I am doing this as three steps. And I am afraid this is not the optimized way. Can someone suggest the ideal way of doing this?
The expected result is
[
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let grouped = [...existingViewers, ...newViewers]
let viewerFilter = grouped.map(viewer => { return viewer.viewerId; });
let filteredPermittedViewers = permittedViewers.filter(viewer => !viewerFilter.includes(viewer.id));
console.log(filteredPermittedViewers)
I'd make a Set of the ids of the first two arrays, and then filter the third by whether the set includes the id. (Sets have O(1) lookup time)
let existingViewers=[{"viewerId":1,"name":"name1"},{"viewerId":2,"name":"name2"}],newViewers=[{"viewerId":3,"name":"name3"}],permittedViewers=[{"id":1,"name":"name1"},{"id":2,"name":"name2"},{"id":3,"name":"name3"},{"id":4,"name":"name4"},{"id":5,"name":"name5"},{"id":6,"name":"name6"}];
const ids = new Set([...existingViewers, ...newViewers].map(({ viewerId }) => viewerId));
const output = permittedViewers.filter(({ id }) => !ids.has(id));
console.log(output);
You can compress all three statements into a single statement -- just replace the variable name with the statement that creates it:
let existingViewers = [{
"viewerId": 1,
"name": "name1"
},
{
"viewerId": 2,
"name": "name2"
}
],
newViewers = [
{
"viewerId": 3,
"name": "name3"
}
],
permittedViewers = [{
"id": 1,
"name": "name1"
},
{
"id": 2,
"name": "name2"
},
{
"id": 3,
"name": "name3"
},
{
"id": 4,
"name": "name4"
},
{
"id": 5,
"name": "name5"
},
{
"id": 6,
"name": "name6"
}
]
let filteredPermittedViewers = permittedViewers.filter(viewer => ! [...existingViewers, ...newViewers].map(viewer => viewer.viewerId).includes(viewer.id));
console.log(filteredPermittedViewers)

How to flatten and merge nested array from each of child array

So i have this data:
let data = [
{
"purchase_id": 1,
"product": [
{
"name": "A",
"id": 1,
"transactions": [
{
"price": 5,
"qty": 2
},
{
"price": 10,
"qty": 2
}
]
},
{
"name": "B",
"id": 2,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
},
{
"purchase_id": 2,
"product": [
{
"name": "C",
"id": 3,
"transactions": [
{
"price": 5,
"qty": 2
}
]
},
{
"name": "D",
"id": 4,
"transactions": [
{
"price": 3,
"qty": 4
}
]
}
]
}
]
And i want to flatten array from each data.product.transactions data:
"transactions": [
{
"price",
"qty"
}
]
Expected output is:
[
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 5,
"qty": 2
},
{
"purchase_id": 1,
"name": "A",
"id": 1,
"price": 10,
"qty": 2
},
{
"purchase_id": 1,
"name": "B",
"id": 2,
"price": 3,
"qty": 4
},
{
"purchase_id": 2,
"name": "C",
"id": 3,
"price": 5,
"qty": 2
},
{
"purchase_id": 2,
"name": "D",
"id": 4,
"price": 3,
"qty": 4
},
]
I have tried to use object assign, reduce but my code doesn't work. Thank you
Use nested Array.map() to create the objects, and spread into Array.concat() to flatten the sub-arrays at each level:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [].concat(...data.map(({ purchase_id, product }) =>
[].concat(...product.map(({ name, id, transactions }) =>
transactions.map((o) => ({
purchase_id,
name,
id,
...o
})
)))));
console.log(result);
If you want to avoid the temp sub-arrays, and the flattering, use nested Array.forEach() calls, and push the created objects to a predefined array:
const data = [{"purchase_id":1,"product":[{"name":"A","id":1,"transactions":[{"price":5,"qty":2},{"price":10,"qty":2}]},{"name":"B","id":2,"transactions":[{"price":3,"qty":4}]}]},{"purchase_id":2,"product":[{"name":"C","id":3,"transactions":[{"price":5,"qty":2}]},{"name":"D","id":4,"transactions":[{"price":3,"qty":4}]}]}];
const result = [];
data.forEach(({ purchase_id, product }) =>
product.forEach(({ name, id, transactions }) =>
transactions.forEach((o) => result.push({
purchase_id,
name,
id,
...o
})
)));
console.log(result);
var arr = [];
data.forEach(x => {
x.product.forEach(y => {
y.transactions.forEach(z => {
z["name"] = y.name;
z["id"] = y.id;
z["purchase_id"] = x.purchase_id;
arr.push(z);
});
})
});
console.log(arr);

Ramda to loop over array

Loop may be the wrong term, but it kind of describes what I am attempting.
I want to give structure to flat data, but I also need to keep track of the array it came from.
Basically my rules are (per array):
If level 1 exists- give it the name of the item, and a typechild array. EACH time a level 1 appears (even in the same array) it should create a new entry.
Inside typechild, put the any items with level >1
If NO level 1 exists- give it the name of the item, and a typechild array.
My code below is almost there, with the exception that it should create an array EVERYTIME it sees a level 1. My example will make sense:
Input data
[
{
"title": "Test 1",
"type": [{
"name": "Animal",
"level": 1
},
{
"name": "Food",
"level": 1
},
{
"name": "Chicken",
"level": 3
}
]
},
{
"title": "Test 2",
"type": [{
"name": "Foo",
"level": 2
}]
}
]
Note: Animal and Food are both LEVEL 1 items. So it should create two ARRAYS like so...
Desired output
[
{
name: "Animal",
typechild: [
{
level: 2,
name: "Chicken"
}
]
},
{
name: "Food",
typechild: [
{
level: 2,
name: "Chicken"
}
]
},
{
name: "NoName",
typechild: [
{
level: 2,
name: "Foo"
}
]
}
]
Ramda attempt (try here: https://dpaste.de/JQHw):
const levelEq = (n) => pipe(prop('level'), equals(n));
const topLevel = pipe(prop('type'), find(levelEq(1)));
const topLevelName = pipe(topLevel, propOr('NoName', 'name'));
const extract2ndLevel = pipe(pluck('type'), flatten, filter(levelEq(2)));
const convert = pipe(
groupBy(topLevelName),
map(extract2ndLevel),
map(uniq),
toPairs,
map(zipObj(['name', 'typechild']))
);
Something like this?
var output = [{
"name": "Animal",
"typechild": [{
"name": "Chicken",
"level": 3
}, {
"name": "Dog",
"level": 2
}]
}, {
"name": "Food",
"typechild": [{
"name": "Chicken",
"level": 3
}]
}, {
"name": "No name",
"typechild": [{
"name": "Foo",
"level": 2
}, {
"name": "Baz",
"level": 2
}]
}]
let out = {},
typechild = {},
k;
const data = [{
"title": "Test 1",
"type": [{
"name": "Animal",
"level": 1
}, {
"name": "Food",
"level": 1
}, {
"name": "Chicken",
"level": 3
}]
}, {
"title": "Test 2",
"type": [{
"name": "Foo",
"level": 2
}]
}, {
"title": "Test 3",
"type": [{
"name": "Baz",
"level": 2
}]
}, {
"title": "Test 4",
"type": [{
"name": "Animal",
"level": 1
}, {
"name": "Dog",
"level": 2
}]
}]
data.forEach((node) => {
k = false;
typechild[node.title] = [];
node.type && node.type.forEach((t, i) => {
if (t.level == 1) {
k = true;
!out[t.name] ? out[t.name] = {
name: t.name,
typechild: typechild[node.title]
} : out[t.name].typechild = out[t.name].typechild.concat(typechild[node.title]);
} else {
typechild[node.title].push(t);
}
if (i == node.type.length - 1 && !k && typechild[node.title].length) {
out['No name'] = out['No name'] || {
name: 'No name',
typechild: []
};
out['No name'].typechild = out['No name'].typechild.concat(typechild[node.title]);
}
});
});
console.log(JSON.stringify(Object.values(out)));

Categories

Resources