Filtering two arrays with .filter [duplicate] - javascript

This question already has answers here:
Simplest code for array intersection in javascript
(40 answers)
Closed 2 years ago.
I'm trying to get information, a have all the data that i get from Database and now I need to do something that should be simple (but not for a novice like me xd), I'm trying to do the next filter in JS
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
console.log(array1.filter(id => id.id == array2.id))
It doesn't returns me nothing, and I don't understand why, also I try to use:
console.log(array1.filter(id => id.id == array2.id))
My result is all the values from array1, I mean I only want the elements that have the same Id that array2 from array1, in other words, I want that its returns me 2 objects with Id = a and one with id = c

Use Array.some() inside Array.filter() callback method.
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
const output = array1.filter(item1 => array2.some(item2 => item2.id === item1.id))
console.log(output);

This will return three objects, because in array1 there are two objects with id: a and one with id: c.
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
let res = array1.filter(obj1 => array2.find(obj2 => obj1.id === obj2.id))
console.log(res)
You can filter out duplicate objects with Array.reduce():
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
let res = array1.filter(obj1 => {
return array2.find(obj2 => obj1.id === obj2.id)
})
.reduce((acc,cur) => {
if(!acc.find(obj => obj.id === cur.id)){
acc.push(cur)
}
return acc
},[])
console.log(res)

You could take a Set and filter the array.
This approach takes a single loop for building the set and another for filtering.
const
array1 = [{ id: 'a' }, { id: '8' }, { id: 'c' }, { id: 'a' }],
array2 = [{ id: 'a' }, { id: 'c' }],
set2 = new Set(array2.map(({ id }) => id)),
result = array1.filter(({ id }) => set2.has(id));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }

You can to use .some to check if array2 has an element with a given id:
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
const res = array1.filter(({id}) => array2.some(e => e.id===id));
console.log(res);
A better way would be using a Set:
const array1 = [{id: 'a'}, {id: '8'}, {id: 'c'}, {id: 'a'}];
const array2 = [{id: 'a'}, {id: 'c'}];
const idsInArray2 = new Set(array2.map(({id}) => id));
const res = array1.filter(({id}) => idsInArray2.has(id));
console.log(res);

Related

Compare two array of objects and remove objects from first array if a property value is matched

I have 2 array of objects like
const arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
Here, I need to compare both these arrays and remove matching objects from arrayOne, which should finally give
this.arrayOne = [{id: 1, name: 'one'}];
I tried like below but it is removing all objects from the array
this.arrayOne = this.arrayOne.filter(o1 => this.arrayTwo.some(o2 => o1.id === o2.id));
What I am doing wrong here? Please suggest. Thanks
const arrayOne = [
{ id: 1, name: "one" },
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwo = [
{ id: 2, name: "two" },
{ id: 3, name: "three" },
];
const arrayTwoIds = new Set(arrayTwo.map((el) => el.id));
const arrayOneFiltered = arrayOne.filter((el) => !arrayTwoIds.has(el.id));
console.log(arrayOneFiltered);
// [ { id: 1, name: 'one' } ]
Depending on the size of the array, creating a set can improve performance, as you do not need to loop over arrayTwo arrayOne.length times but only once. After that, you can look up the existence of an id in arrayTwo in constant time.
Yet, as pointed out in another answer, this is not necessary if the arrays are small (like in your example). In this case, you could also use this one-liner:
arrayOne = arrayOne.filter((elOne) => !arrayTwo.some((elTwo) => elOne.id === elTwo.id));
Here, arrayOne would need to be mutable, i.e. defined with let.
You can find it by comparing it with id.
And arrayOne must be a let.
let arrayOne = [{id: 1, name: 'one'}, {id: 2, name: 'two'}, {id: 3, name: 'three'}];
const arrayTwo = [{id: 2, name: 'two'}, {id: 3, name: 'three'}];
arrayOne = arrayOne.filter(one => !arrayTwo.find(two => one.id == two.id));
console.log(arrayOne);
const arrayOne = [{
id: 1,
name: 'one'
}, {
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwo = [{
id: 2,
name: 'two'
}, {
id: 3,
name: 'three'
}];
const arrayTwoId = arrayTwo.map(el => (el.id)); // extract id from arrayTwo
const result = arrayOne.filter(el => !arrayTwoId.includes(el.id));
console.log(result);
Extract all the ids from the arrayTwo.
filter those objects who do not match the array of ids of arrayTwo.
Your way is correct. but you miss the not operation (!) before arrayTwo.some.
So the correct way is this:
const arrayOne = [
{id: 1, name: 'one'},
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
const arrayTwo = [
{id: 2, name: 'two'},
{id: 3, name: 'three'}
];
// Shared Items between arrayOne and arrayTwo (this what you done)
const sharedObjects = arrayOne.filter(o1 => arrayTwo.some(o2 => o1.id === o2.id));
console.log(sharedObjects);
// arrayOne - arrayTwo (this is what you want)
const arrayOneUniqueObjects = arrayOne.filter(o1 => !arrayTwo.some(o2 => o1.id === o2.id));
console.log(arrayOneUniqueObjects);
Also, You can find more details here:
bobbyhadz.com/blog/javascript-get-difference-between-two-arrays-of-objects

display entire array after moving values of it to another array

I have an array containing objects where there is a rpId key in some of the objects. The goal is to separate/move the objects that return undefined to a separate array and remove them out of the first array.
e.g.:
results = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
goal: results = [{id: 2, rpId: 1076}, {id: 4, rpId: 303}] and stations = [{id: 1}, {id: 3}]
My current approach can be seen below. As visible, I get a wrong array1 because it contains an object with a rpId, plus array2 returns the keys of the object and I'd like to read the entire object, not just the "undefined" of the key.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const array2 = [];
const mapping = array1.map((e) => e.rpId);
console.log("mapping",mapping);
mapping.forEach(function(elem, index){
elem === undefined ? array2.push(elem) && array1.splice(index, elem === undefined) && console.log(elem): console.log("defined", elem);
}),
console.log("1", array1); // [{ id: 2, rpId: 1076 }, { id: 3 }]
console.log("2", array2); // [undefined, undefined]
Just check if the rpId property is undefined in each element.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const array2 = [];
array1.forEach(function(elem, index){
if(elem.rpId === undefined)
array2.push(elem) && array1.splice(index, 1)
});
console.log(array1);
console.log(array2);
One can also use Array#filter or push elements into two separate arrays based on the condition for better performance.
const array1 = [{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}];
const yes = [], no = [];
array1.forEach(elem=>(elem.rpId!==undefined?yes:no).push(elem));
console.log(yes);
console.log(no);
You can use filter too:
let results = [
{ id: 1 },
{ id: 2, rpId: 1076 },
{ id: 3 },
{ id: 4, rpId: 303 },
];
const stations = results.filter((c) => !c.rpId);
results = results.filter((c) => c.rpId);
console.log("stations", stations);
console.log("results", results);
const GiveItACreativeName = (arr) => {
const result = []
const stations = []
arr.forEach((el) => {
if('rpId' in el) result.push(el);
else stations.push(el);
});
return {result, stations}
}
console.log(
GiveItACreativeName([{id: 1}, {id: 2, rpId: 1076}, {id: 3}, {id: 4, rpId: 303}])
);

how get common elements of 2 different arrays and return an object containing the common elements

I have 2 arrays of objects
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
and I want to get a new the array1 such that
var array = [
{id: 1, name:'fruit'},
{id: 4, name:'vegetable'},
]
which has only the elements with quantity 2 matching the alimentId with the id.
I'm always getting confused with arrays and objects manipulations.. Please help
I believe the following code will solve your problem:
const func = (arr1, arr2) => {
return arr1.filter(obj => {
const objToCheck = arr2.filter(element => element.alimentId === obj.id);
return objToCheck[0].quantity === 2;
});
};
You also can send the wanted value(2) and the key name(quantity) as params.
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
function filter(array1, array2) {
return array1
.filter(it => array2 // filter array1 by array2
.filter(it => it.quantity === 2) // filter your array2 by field quantity = 2
.map(it => it.alimentId) // pull out array of alimentId
.includes(it.id) // check array2.alimentId includes array1.id
)
}
console.log(filter(array1, array2))
use this function
const common_elements = (arr1, arr2, quantity) => {
let res = []
arr1.forEach(el1 => {
arr2.forEach(el2 => {
if(el1.id === el2.alimentId && el2.quantity === quantity) {
res.push(el1)
}
});
});
return res
}
You can do a reduce:
var array3 = array1.reduce((acc ,val ,index) => {
if (val.id=array2[index].alimentId) {
acc =[...acc, {id: val.id, name: val.name}]
}
return acc;
},[]);
var array1 = [
{id: 1, name:'fruit', rating:5},
{id: 4, name:'vegetable', rating: 3},
{id: 8, name:'meat', rating:1}
];
var array2 = [
{alimentId: 1, quantity: 2},
{alimentId: 4, quantity: 2},
{alimentId: 8, quantity: 4}
]
const commonArray = array2.filter(item => item.quantity === 2 && array1.find(el => el.id===item.alimentId));
console.log(commonArray)

Convert array of objects in an array of array of objects [duplicate]

This question already has answers here:
How can I group an array of objects by key?
(32 answers)
Closed 2 years ago.
I am retrieving data from a football (soccer) API. The specific data I need is an array of objects (306 objects). Every object has a property called matchday with a numeric value. I want to group all the objects that share the same property and store them in an array. What I need in the end is an array of array of objects.
Example array of objects:
[
{id: 264796, matchday: 1, …},
{id: 264797, matchday: 1, …},
{id: 264798, matchday: 2, …},
{id: 264800, matchday: 2, …},
]
What I want looks like this:
[
[{id: 264796, matchday: 1, …},{id: 264797, matchday: 1, …}],
[{id: 264798, matchday: 2, …},{id: 264800, matchday: 2, …}],
]
You can use .reduce() with Object.values() to get the desired output:
const data = [
{id: 264796, matchday: 1}, {id: 264797, matchday: 1},
{id: 264798, matchday: 2}, {id: 264800, matchday: 2}
];
const result = Object.values(
data.reduce((r, c) => {
r[c.matchday] = r[c.matchday] || [];
r[c.matchday].push(c);
return r;
}, {})
);
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
we can use reduce
const arr = [
{id: 264796, matchday: 1},
{id: 264797, matchday: 1},
{id: 264798, matchday: 2},
{id: 264800, matchday: 2},
]
const result = arr.reduce((acc, item) => {
if (!acc.find(accSubArr => accSubArr.find(accSubArrItem => accSubArrItem.matchday === item.matchday))) {
acc.push(arr.filter(arrItem => arrItem.matchday === item.matchday))
}
return acc;
}, [])
console.log(result)
You can try this:
const data = [{
id: 264796,
matchday: 1
},
{
id: 264797,
matchday: 1
},
{
id: 264798,
matchday: 2
},
{
id: 264800,
matchday: 2
},
]
const group = data
.map(d => d.matchday)
.filter((v, i, c) => c.indexOf(v) === i)
.map(i => data.filter(d => d.matchday === i))
console.log(group)
To add to the existing answers, here's another way making use of Map with a predicate to determine the group-by value:
const groupBy = predicate => items =>
Array.from(items.reduce((agg, next) => {
const key = predicate(next);
return agg.set(key, [].concat(agg.get(key) || []).concat(next));
}, new Map()).values());
const data = [
{name: 'A', key: 1},
{name: 'B', key: 1},
{name: 'C', key: 2},
{name: 'D', key: 2},
{name: 'E', key: 3}
];
const grouped = groupBy(x => x.key)(data);
For the fun of it, here's a recursive version of groupBy:
const groupBy = predicate => function group([next, ...items], grouped = new Map()) {
if (!next) {
return Array.from(grouped.values())
}
const key = predicate(next);
return group(items, grouped.set(key, [...(grouped.get(key) || []), next]));
}
And what the heck, here's a more imperative approach to add to the mix:
const groupBy = predicate => items => {
const cache = {};
for(item of items) {
const key = predicate(item);
cache[key] = [].concat(cache[key]).concat(item).filter(x => x)
}
return Object.values(cache);
}

Remove same Values from array of Object

I want to remove same object from array by comparing 2 arrays.
Sample Data:
arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = []; // new array with with no same values it should be unique.
arr1.map((val, i)=>{
arr2.map((val2)=>{
if(val.id == val2.id){
console.log('Matched At: '+ i) // do nothing
}else{
newArray.push(val);
}
})
})
console.log(newArray); // e.g: [{id: 2, name: "b"}, {id: 3, name: "c"},];
Array.filter combined with not Array.some.
The trick here is also to not some,..
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
], arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const newArray=arr1.filter(a=>!arr2.some(s=>s.id===a.id));
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
As mentioned in comments the question could be interpreted slightly differently. If you also want the unqiue items from arr2, you basically just do it twice and join. IOW: check what not in arr2 is in arr1, and then check what not in arr1 that's in arr2.
eg..
const notIn=(a,b)=>a.filter(f=>!b.some(s=>f.id===s.id));
const newArray=[...notIn(arr1, arr2), ...notIn(arr2, arr1)];
Update 2:
Time complexity, as mentioned by qiAlex there is loops within loops. Although some will short circuit on finding a match, if the dataset gets large things could slow down. This is were Set and Map comes in.
So to fix this using a Set.
const notIn=(a,b)=>a.filter(a=>!b.has(a.id));
const newArray=[
...notIn(arr1, new Set(arr2.map(m=>m.id))),
...notIn(arr2, new Set(arr1.map(m=>m.id)))
];
const isInArray = (arr, id, name) => arr.reduce((result, curr) => ((curr.name === name && curr.id === id) || result), false)
const newArray = arr1.reduce((result, curr) => (isInArray(arr2, curr.id, curr.name) ? result : result.concat(curr)), [])
You can update you code using filter() method, instead of using .map() method like:
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
], arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = []; // new array with with no same values it should be unique.
newArray = arr1.filter(function(a) {
for(var i=0; i < arr2.length; i++){
if(a.id == arr2[i].id) return false;
}
return true;
});
console.log(newArray);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You check each element in first array whether its id lies in the second array by using Array.prototype.some. If the element is not present then only yield it.
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
const arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const result = arr1.filter(x => !arr2.some(y => y.id === x.id));
console.log(result);
I think a simple comparer can works for getting differences and then concat them.
with this method you dont need to check which array is bigger.
arr1 = [ {id: 1, name: "a"}, {id: 2, name: "b"}, {id: 3, name: "c"}, {id: 4, name: "d"}];
arr2 = [ {id: 1, name: "a"}, {id: 4, name: "d"},];
function localComparer(b){
return function(a){
return b.filter(
function(item){
return item.id == a.id && item.name == a.name
}).length == 0;
}
}
var onlyInArr1 = arr1.filter(localComparer(arr2));
var onlyInArr2 = arr2.filter(localComparer(arr1));
console.log(onlyInArr1.concat(onlyInArr2));
We can filter values by checking whether some element is not contained in current array:
const result = arr1.reduce((a, c) => {
if (!arr2.some(a2 => a2.id === c.id))
a.push(c);
return a;
}, [])
An example:
let arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
let arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const result = arr1.reduce((a, c) => {
if (!arr2.some(a2 => a2.id === c.id))
a.push(c);
return a;
}, [])
console.log(result);
Try this one -
const arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
const arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
const arr3 = [...arr1, ...arr2];
const mySubArray = _.uniq(arr3, 'id');
console.log(mySubArray);
<script src="https://cdnjs.cloudflare.com/ajax/libs/underscore.js/1.9.1/underscore-min.js"></script>
So many loops in every answer.
Complexity of the code my answer is 2N,
Idea is:
to merge arrays.
first loop - mark duplicates somehow
second loop - filter duplicates out
arr1 = [
{id: 1, name: "a"},
{id: 2, name: "b"},
{id: 3, name: "c"},
{id: 4, name: "d"},
];
arr2 = [
{id: 1, name: "a"},
{id: 4, name: "d"},
];
let newArray = [...arr1, ...arr2].reduce((acc, item, index) => {
acc.items.push(item);
if (typeof acc.map[item.id] !== 'undefined') {
acc.items[acc.map[item.id]] = null;
acc.items[index] = null;
}
acc.map[item.id] = index;
return acc
}, {map: {}, items: []}).items.filter(item => !!item)
console.log(newArray);

Categories