I have to remove all the objects from array that contain the same id present in another array.
This code works
myArray = [{id: 1, value: 'a'}, {id: 2, value: 'b'}, {id: 3, value: 'c'}];
itemsToRemove = [{id: 2, value: 'x'}, {id: 3, value: 'y'}];
for (const item of itemsToRemove) {
myArray.splice(myArray.findIndex(a => a.id === item.id), 1);
}
but I'm looking for a more elegant way to do it. I've tried also
const newArray = myArray.filter(a => itemsToRemove.findIndex(i => i.id === a.id));
but doesn't works. (it creates a new array, but at least one item with the same id remains in the new array).
Is there a clean and concise way to do it?
You're close, but as James said in the comments, findIndex is the wrong choice because it returns -1 when the item is not found. filter requires its predicate to return a boolean and -1 is not a boolean, so it's coerced to one. Unfortunately, -1 is truthy which doesn't match your intention in the predicate.
You can add a comparison to check that findIndex returned a value less than zero, or you can use find or some:
const myArray = [{id: 1, value: 'a'}, {id: 2, value: 'b'}, {id: 3, value: 'c'}];
const itemsToRemove = [{id: 2, value: 'x'}, {id: 3, value: 'y'}];
const newArray1 = myArray.filter(a => itemsToRemove.findIndex(i => i.id === a.id) < 0);
console.log(newArray1);
const newArray2 = myArray.filter(a => !itemsToRemove.find(i => i.id === a.id));
console.log(newArray2);
const newArray3 = myArray.filter(a => !itemsToRemove.some(i => i.id === a.id));
console.log(newArray3);
It's worth noting that find isn't supported in IE, nor is findIndex. some is supported by all browsers, so it's the most compatible.
some is also the most performant:
Test
Result
Operations/second
findIndex
10.63% slower
26632285
find
12.39% slower
26107649
some
fastest
29799972
Related
having an array of element like this :
names = [
{id: 1, name: "toto"},
{id: 2},
{id: 3, name: "lala"}
]
i would like to remove elements where the value of name is null or not present or empty with typescript
i've tried:
names.filter(name => name.name !== null);
When there is no corresponsing property, name.name returns undefined, not null.
Use either of those:
names.filter(name => name.name != null);
names.filter(name => name.name !== undefined);
names.filter(name => name.name)
var data = [
{id:1,name:"toto"},
{id:2},
{id:3,name:"lala"}
]
data.filter(item => item.name)
result: [{id: 1, name: "toto"}, {id: 3, name: "lala"}]
You can simply add a check if the name property exists and is not null/undefined by checking name.name. See the following example.
names = [
{id: 1, name: "toto"},
{id: 2},
{id: 3, name: "lala"}
];
console.log(names.filter(name => name.name));
I think the most elegant solutoin is a filter loop. You can just copy-past the "filter" method
let names = [
{id:1,name:"toto"},
{id:2},
{id:3,name:"lala"}
];
let removedObject = names.filter(name => !name.name);
let newArrayWithOnlyNamedSubjects = names.filter(name => name.name);
console.log(removedObject); // [{ id: 2 }]
console.log(newArrayWithOnlyNamedSubjects); //[{id: 1, name: "toto"}, {id: 3, name: "lala"}]
You can filter for names which are valid:
names.filter(name => name.name);
I have following :
const arr1 = [{id: 1},{id: 2}]
const arr2 = [{id: 1},{id: 4},{id: 3}]
I want to check if elements in arr2 exists in arr1 or vice versa. I want to check for each element in array.
Desired output :
true
false
false
Usually it shouls give error , because one arrays length is longer than first , for the rest I want to get false
O(N) solution with set
const arr1 = [{id: 1},{id: 2}]
const arr2 = [{id: 1},{id: 4},{id: 3}]
const set = new Set()
arr1.forEach((a) => set.add(a.id))
arr2.forEach((b) => {
if (set.has(b.id)) {
console.log("arr1 and arr2 both share"+ b.id)
}
})
You can use array#map with array#some to check if object id in arr2 exist in arr1.
const arr1 = [{id: 1},{id: 2}],
arr2 = [{id: 1},{id: 4},{id: 3}],
result = arr2.map(({id}) => arr1.some(o => id === o.id));
console.log(result);
const arr1 = [{
id: 1
}, {
id: 2
}]
const arr2 = [{
id: 1
}, {
id: 4
}, {
id: 3
}]
let arr1id = arr1.map(i => i.id);
let result = arr2.map(a => arr1id.includes(a.id));
console.log(result);
use hashmap & use below 2 methods of map in java
boolean containsKey(Object key)
V get(Object key)
V get(Object key) to get the object that contains the value associated with the key from map1.
boolean containsKey(Object key) This method returns true if some key equal to the key exists within the map, else return false [ check it in map2]
This question already has answers here:
How to filter an array from all elements of another array
(24 answers)
Closed 2 years ago.
I can't seem to find a solution to this, how do you remove items from an array based on an array of values? The same way you remove one?
const [items, setItems] = useState([
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
])
I need to remove some ids:
const idsToRemove = [1,3]
// I thought I'd loop
idsToRemove.map(i => items.filter(item => item.id !== i))
This will return an array and something does not feel right at all. If it was to remove one item then that would be ok but removing items from array by an array of ids I not know where to start.
In the loop, I tried to use delete but "undefinded" is in the array: [undefined]:
idsToRemove.map(i => items.map(item => delete item.id === i))
So far React says you cannot update state during a loop. Based on idsToRemove, how can I end up with one item in the state?
You need to put the filter call outside:
items.filter(item => !idsToRemove.includes(item.id))
You can use filter with includes.
items = items.filter(({id})=>!idsToRemove.includes(id));
let items = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
];
const idsToRemove = [1,3]
items = items.filter(({id})=>!idsToRemove.includes(id));
console.log(items);
const items = [
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
];
const idsToRemove = [1, 3];
console.log(
items.filter(({ id }) => !idsToRemove.includes(id))
);
const [items, setItems] = useState([
{id: 1, name: "foo"},
{id: 2, name: "bar"},
{id: 3, name: "baz"}
]
const idsToRemove = [1,3]
setItems(items.filter((item)=> !idsToRemove.includes(item.id)))
using functional programming you won't be changing the current state obj but creating a new one, hence maintaining the sanity of React immutability.
I have an array of objects lookups and an array filters. Now I want to filter the array from an array of objects using the object attribute name.
I used filter and some but I could not get the expected result.
EXPECTED RESULT:
[{id: 3, name: "Linkedin"}]
let lookups = [
{id: 1, name: "Twitter"},
{id: 2, name: "Facebook"},
{id: 3, name: "Linkedin"}
]
let filters = ["Facebook", "Twitter"]
const filtered = lookups.filter(lookup => filters.some(filter => filter.toLowerCase() != lookup.name.toLowerCase()));
console.log(filtered)
Your code gives those elements in result for which some of the values in filters is not equal to element's name. So for each element some of the name is not equal.
In other words you are using != with || which will always return true.
let a = "anything";
console.log(a !== "thing1" || a !== "thing2")
You need to use every() instead of some().
let lookups = [
{id: 1, name: "Twitter"},
{id: 2, name: "Facebook"},
{id: 3, name: "Linkedin"}
]
let filters = ["Facebook", "Twitter"]
const filtered = lookups.filter(lookup => filters.every(filter => filter.toLowerCase() !== lookup.name.toLowerCase()));
console.log(filtered)
I need to know if an array of objects contains at least two same objects in it, in JavaScript.
I have a form that allow people to create questions (title, description, type, answer options). I need to check whether the user has entered multiple answer options with the same label. They are stored in an array.
// The array of answer options
let array = [{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}]
I tried using array.indexOf({value: 'a'}) and array.lastIndexOf({value: 'a'}) but they both give me an index of -1.
Separate objects are never === to each other, so you'll have to use a different method. One option is to create a Set of the stringified objects, and return true once any duplicate string is found:
const hasDupes = (arr) => {
const strings = new Set();
for (const obj of arr) {
const string = JSON.stringify(obj);
if (strings.has(string)) {
return true;
}
strings.add(string);
}
return false;
};
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}]));
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}]));
If you are only concerned about the value property and you use case is not more complex and you can simply do this in one line via:
let hasDupes = arr => new Set(arr.map(x => x.value)).size !== arr.length
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'},{value: 'a'}]))
console.log(hasDupes([{value: 'a'}, {value: 'b'}, {value: 'c'}]))
You would use Set to add the values of value and if the size of it is smaller than the actual input array length than you had duplicates. There is no need to do JSON.stringify, compare strings etc if you only care about that one property being checked.
Also JSON.stringify has issues when comparing equality of objects.
Use findIndex:
let array = [{value: 'a'}, {value: 'b'}, {value: 'c'}, {value: 'a'}];
const index = array.findIndex(({ value }) => value == "a");
console.log(index);
indexOf will return the instance of an object
{value: 'a'} !== {value: 'a'};
as they are both different instances of objects.
You can find the object
const obj = array.find(item => item.value === 'a')
You can use lodash.js to compare two objects.
Please see the sample below.
let array = [{ value: "a" }, { value: "b" }, { value: "c" }, { value: "a" }];
const object = { value: "a" };
countObjOccurrences = object => {
let occurances = 0;
array.map(item => {
if (_.isEqual(item, object)) {
occurances += 1;
}
});
return occurances;
};
This function will return 2.