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/
Related
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?
This question already has answers here:
How to merge multiple array of object by ID in javascript?
(5 answers)
Closed 1 year ago.
Input arrays
arr1=[{"CATALOG":"book1","ID":"1"},{"CATALOG":"book2","ID":"2"},{"CATALOG":"book3","ID":"3"},{"CATALOG":"book4","ID":"12"}]
arr2=[{"NAME":"TOM","ID":"1"},{"NAME":"STEVE","ID":"22"},{"NAME":"HARRY","ID":"2"},{"NAME":"TIM","ID":"3"},{"NAME":"DAVE","ID":"12"},{"NAME":"WIL","ID":"12"},{"NAME":"PETER","ID":"94"},{"NAME":"SAVANNAH","ID":"77"}]
Expected Output
[{"CATALOG":"book1","ID":"1","NAME":"TOM"},
{"CATALOG":"book2","ID":"2","NAME":"HARRY"},
{"CATALOG":"book3","ID":"3","NAME":"TIM"},
{"CATALOG":"book4","ID":"12","NAME":"WIL"}
expected output is that 2 arrays have to be combined based on id. If ID doesn't exist then that particular object is skipped
I tried using
[arr1,arr2].reduce((a, b) => a.map((c, i) => Object.assign({}, c, b[i])));
But not getting the desired output
You can use map and find
const arr1 = [
{ CATALOG: "book1", ID: "1" },
{ CATALOG: "book2", ID: "2" },
{ CATALOG: "book3", ID: "3" },
{ CATALOG: "book4", ID: "12" },
];
const arr2 = [
{ NAME: "TOM", ID: "1" },
{ NAME: "STEVE", ID: "22" },
{ NAME: "HARRY", ID: "2" },
{ NAME: "TIM", ID: "3" },
{ NAME: "DAVE", ID: "12" },
{ NAME: "WIL", ID: "12" },
{ NAME: "PETER", ID: "94" },
{ NAME: "SAVANNAH", ID: "77" },
];
const output = arr1.map(a => ({
...a,
NAME: arr2.find(x => x.ID === a.ID).NAME,
}));
console.log(output);
There may be cleverer solutions, but assuming arr2 always contains the corresponding ID, I'd do it simply with :
const arr1=[{"CATALOG":"book1","ID":"1"},{"CATALOG":"book2","ID":"2"},{"CATALOG":"book3","ID":"3"},{"CATALOG":"book4","ID":"12"}];
const arr2=[{"NAME":"TOM","ID":"1"},{"NAME":"STEVE","ID":"22"},{"NAME":"HARRY","ID":"2"},{"NAME":"TIM","ID":"3"},{"NAME":"DAVE","ID":"12"},{"NAME":"WIL","ID":"12"},{"NAME":"PETER","ID":"94"},{"NAME":"SAVANNAH","ID":"77"}];
const output = arr1.map(obj1 => {
const obj2 = arr2.find(o2 => o2.ID === obj1.ID);
return Object.assign(obj1, obj2)
});
console.log(output)
Or as a one-liner :
const output = arr1.map(obj1 => Object.assign(obj1, arr2.find(o2 => o2.ID === obj1.ID)))
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);
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);
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