JavaScript Array Filtering in Nested Arrays - javascript

I have an array that looks something like this:
const arrayObj = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [
{
name: "Jack",
},
{
name: "Man",
},
],
},
]
What I want is to filter the objects whose itemsList contain an object with the name of a certain value. For example, I want to be able to filter out an array with objects whose inner objects with names that contain "ul" (in this case the name Paul contains "ul"), it should give me an output as such:
const outputArray = [
{
id: 1,
itemsList: [
{
name: "Paul",
},
{
name: "Newman",
},
]
}
]
So far, I've only been able to filter out a simple flat array of objects with this function:
function filterByName(array: any, string: any) {
return array.filter((obj: any) =>
["name"].some((key: any) =>
String(obj[key]).toLowerCase().includes(string.toLowerCase())
)
);
}
but I don't know how to apply it to my case.

Here you can use the some method combined with the includes method
const arrayObj = [{
id: 1,
itemsList: [{
name: "Paul",
},
{
name: "Newman",
},
],
},
{
id: 2,
itemsList: [{
name: "Jack",
},
{
name: "Man",
},
],
},
]
const getFilterArray = (name) => {
return arrayObj.filter(obj => obj.itemsList.some(x => x.name.toLowerCase().includes(name.toLowerCase())))
}
console.log(getFilterArray("ul"))

const result = arrayObj.filter(({ itemsList }) =>
itemsList.some(({ name }) => name.toLowerCase().includes('ul')));
Can you try this?

Related

compare and filter 2 arrays

I have 2 arrays. I need to show only data which does not match with the second array.
array1 = [
{
country: "usa",
child: [
{ id: 1, name: "fvsdfsd" },
{ id: 2, name: "hhghhhfhj" },
],
},
{
country: "CA",
child: [
{ id: 3, name: "adsada" },
{ id: 4, name: "hhghhhfhj" },
],
},
{
country: "AU",
child: [
{ id: 5, name: "seven" },
{ id: 6, name: "hhghhhfhj" },
],
},
];
array2 = [
{ id: 1, name: "fvsdfsd" },
{ id: 2, name: "hhghhhfhj" },
];
result:
[
{
country: "usa",
child: [],
},
{
country: "CA",
child: [
{ id: 3, name: "adsada" },
{ id: 4, name: "hhghhhfhj" },
],
},
{
country: "AU",
child: [
{ id:5, name: "seven" },
{ id:6, name: "hhghhhfhj" },
],
},
]
I try like this but its not working
array1.filter(data => !array2.includes(data.child));
Your code is not working because of how Ecma/Javascript does equality testing. Array.includes() uses the sameValueZero algorithm for determining if two things are "equal".
[And equality in Javascript is odd]
Object comparison is done by reference, so two object are equal if (and only if) they are the exact same object in memory. For instance
const areEqual = {a:1,b:2} === {a:1,b:2}
is false, as is
const areEqual = {a:1,b:2} == {a:1,b:2}
You need to do deep equality checking with something like lodash's isEqual():
const _ = require('lodash');
const areEqual = _.isEqual( {a:1,b:2} , {a:1,b:2} ) ; // returns true
So you should be able to say something like:
const _ = require('lodash');
const filtered = array1.map( o => {
return {
...o,
child: _.isEqual( o.child, array2 ) ? [] : o.child ),
}
});
Yeah, you can try like this.
array1.map(item1 => ({ ...item1, child: item1.child.filter(childItem => !array2.find(item2 => JSON.stringify(item2) === JSON.stringify(childItem))) }));
If the keys of the object are not in the same order, as Everett Glovier said, you can try like this.
array1.map(item1 => ({ ...item1, child: item1.child.filter(childItem => !array2.find(item2 => item2.id === childItem.id && item2.name === childItem.name)) }));
You cannot compare two different objects using includes in javascript, because includes uses ===. Only references to the same object will return true using ===. You'll need to write a custom function that runs through all of the keys of your object and compares their values between your two arrays.
This article explains some techniques for comparing two objects:
https://dmitripavlutin.com/how-to-compare-objects-in-javascript/

Lodash group by specific words/prefix in a key

I wonder how I can group this array based on the prefix text in name key (split the name key at the : colon) using Lodash.
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
to
const tags = [{
animals: [
{ name: 'Frogs', id: 1 },
{ name: 'Lions', id: 2 },
],
birds: [
{ name: 'Crows', id: 3}
]
}];
Does Lodash have any functions to handle this, or is a custom function/regex needed?
If the pure JS suffices, it can be done this way (the result is an object here, not an array, but this can be changed if needed):
const tags = [
{ name: 'Animals: Frogs', id: 1 },
{ name: 'Animals: Lions', id: 2 },
{ name: 'Birds: Crows', id: 3 }
];
const tags2 = tags.reduce(
(acc, { name, id }) => {
let [group, type] = name.split(': ');
group = group.toLowerCase();
acc[group] ??= [];
acc[group].push({ name: type, id });
return acc;
},
{},
);
console.log(tags2);

Filter an object iside an array

I need to delete entire object that do not have passed
here is the array
const array = [{
course: 1,
list: [{
id: 1,
name: "john",
code: true
},
{
id: 1,
name: "maria",
code: true
},
]
},
{
course: 2,
list: [{
id: 3,
name: "rose"
},
{
id: 4,
name: "mark",
code: true
}
]
}
]
That i need is remove obj that not have code:true, and get this
const array = [{
course: 1,
list: [{
id: 1,
name: "john",
code: true
}, ]
},
{
course: 2,
list: [{
id: 1,
name: "mark",
code: true
}]
}
]
I tried to make a map inside a filter, but it does not work at all
const remove = array.filter(function(lines) {
return lines.map(line => line.list.map(list => list.code))
});
You can map through the array, then copy all properties of the specific item and separately do the filtering on the list attribute.
const array = [{
course: 1,
list: [{
id: 1,
name: "john",
code: true
},
{
id: 1,
name: "maria",
code: true
},
]
},
{
course: 2,
list: [{
id: 3,
name: "rose"
},
{
id: 4,
name: "mark",
code: true
}
]
}
]
const filter = arr => arr.map(arrItem => ({
...arrItem,
list: arrItem.list.filter( listItem => listItem.code )
})
)
console.log( filter(array) )
const filtered = [];
arr.forEach(item => {
const list = item.list.filter(listItem => listItem.code);
if(list.length > 0) {
filter.push({ ...item, list });
}
});
This approach will only add items to the filtered output array if the list contains any items after filtering out those with code: false. To include them anyway, you could do:
const filtered = arr.map(item => ({
...item,
list: item.list.filter(listItem => listItem.code)
});

Return deconstructed array in object with es6 map

I want to return a deconsturcted array so I only get single element in te returned array instead of array.
const data = [
{
title: 'amsterdam',
components: [
{
id: 1,
name: 'yanick',
},
{
id: 2,
name: 'ronald',
},
],
},
{
title: 'rotterdam',
components: [
{
id: 4,
name: 'nicky',
},
{
id: 3,
name: 'casper',
},
],
},
];
const test = data
.map(item => {
console.log(item.components);
return item.components;
}).map(array => {
// how to get comibned components here?
// it can't use ...item.components (deconstructing or something)
});
console.log('test', test);
So I want to use chained map functions to create one array of all elements in item.components. Is this possible? Seems like I can't deconstruct the array of each item.
Array.prototype.reduce seems like the correct method to use in this context.
const test = data.reduce( (result, current) => result.concat(current.components) , []);
console.log('test', test);
Output
test [ { id: 1, name: 'yanick' },
{ id: 2, name: 'ronald' },
{ id: 4, name: 'nicky' },
{ id: 3, name: 'casper' } ]
Get the components with Array.map(), and flatten by spreading into Array.concat():
const data = [{"title":"amsterdam","components":[{"id":1,"name":"yanick"},{"id":2,"name":"ronald"}]},{"title":"rotterdam","components":[{"id":4,"name":"nicky"},{"id":3,"name":"casper"}]}];
const result = [].concat(...data.map(o => o.components));
console.log(result);
To get data combined into single array you can use reduce in combination with concat that will create a single array of results.
const data = [
{
title: 'amsterdam',
components: [
{
id: 1,
name: 'yanick',
},
{
id: 2,
name: 'ronald',
},
],
},
{
title: 'rotterdam',
components: [
{
id: 4,
name: 'nicky',
},
{
id: 3,
name: 'casper',
},
],
},
];
const test = data
.map(item => {
return item.components;
}).reduce((res, item) => {
return res.concat(item);
}, []);
console.log('test', test);

double nested array of object es6 filter

I want to filter out a nested array of objects but stuck at the filter part.
How to remove one of the mark?
this.state = {
data: [
{
id: 1,
name: "Main",
subs: [
{
id: "jay",
name: "Jay",
mark: [
{
id: "5a5d84b94a074c49ef2d4553",
name: 100
},
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}
]
}
]
};
https://codesandbox.io/s/p39momxzp7
I try to use es6 as it's more readable.
expected output
data: [
{
id: 1,
name: "Main",
subs: [
{
id: "jay",
name: "Jay",
mark: [
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}
]
}
]
Since there are multiple nested arrays in your data structure, you need to use forEach those many times
data.forEach( s => //iterate data
s.subs.forEach( t => //iterate subs
( t.mark = t.mark.slice( 1, 2 ) ) ) ); //slice the second value out
Demo
var data = [{
id: 1,
name: "Main",
subs: [{
id: "jay",
name: "Jay",
mark: [{
id: "5a5d84b94a074c49ef2d4553",
name: 100
},
{
id: "5a5d84b94a074119ef2d4553",
name: 70
}
]
}]
}];
data.forEach(s => s.subs.forEach(t => (t.mark = t.mark.slice(1,2))));
console.log(JSON.stringify(data, 0, 4))
In case the last value should be picked?
data.forEach( s => //iterate data
s.subs.forEach( t => //iterate subs
( t.mark = t.mark.slice( -1 ) ) ) ); //slice the last value out
If you are trying to filter a relevant mark by a given id,
you can combine Array#map and Array#filter to achieve it:
Note that i'm also using the Object Rest/Spread Properties proposal (stage 4)
Running example
const state = {
data: [{
id: 1,
name: "Main",
subs: [{
id: "jay",
name: "Jay",
mark: [{
id: "5a5d84b94a074c49ef2d4553",
name: 100
}, {
id: "5a5d84b94a074119ef2d4553",
name: 70
}]
}]
}]
};
const mark_id = '5a5d84b94a074119ef2d4553';
const nextState = {
...state,
data: state.data.map(obj => {
const filteredSubs = obj.subs.map(sub => {
const markById = sub.mark.filter(m => m.id === mark_id);
return {
...sub,
mark: markById
}
});
return {
...obj,
subs: filteredSubs
}
})
};
console.log(nextState);
You can even use lodash which contains many methods that can be handled easily.
Check if this is what you are looking for. (there is a good scope to refactor it but before that would like to understand if thats what you are looking for)
Below is the code that has been used there.
let inputId = "5a5d84b94a074c49ef2d4553";
let filteredData =_.each(_.cloneDeep(data), function(value, key1) {
_.each(value.subs, function(valueSubs, key2) {
var finalSubMark = _.find(valueSubs.mark, function(eachMark) {
return eachMark.id == inputId;
});
_.set(valueSubs, "mark", finalSubMark);
});
});
https://codesandbox.io/s/v065w05rly

Categories