Remove items from array based on array of values [duplicate] - javascript

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.

Related

Transform array of objects to nested objects using Ramda

I am a newbie so pardon me if I ask a naive question.
I have an array of objects
const arr = [{id: 1, name: 'Pete'}, {id: 5, name: 'John'}, {id: 3, name: 'Peter'}]
and I want to convert it to this form using ramda:
const obj = {1 : {id: 1, name: 'Pete'}, 5: {id: 5, name: 'John'}, 3: {id: 3, name: 'Peter'}}
Can anyone please help?
Other Conceptual Questions:
I want to convert nested array of objects to this form because that way searching a name will be quick if id is given. Is this the right approach?
Is there any other efficient way performance wise that can make the search in array quicker?
Thanks
You can use ramda's R.indexBy:
const arr = [{id: 1, name: 'Pete'}, {id: 2, name: 'John'}, {id: 3, name: 'Peter'}]
const result = R.indexBy(R.prop('id'))(arr)
console.log(result)
<script src="https://cdnjs.cloudflare.com/ajax/libs/ramda/0.27.1/ramda.min.js" integrity="sha512-rZHvUXcc1zWKsxm7rJ8lVQuIr1oOmm7cShlvpV0gWf0RvbcJN6x96al/Rp2L2BI4a4ZkT2/YfVe/8YvB2UHzQw==" crossorigin="anonymous"></script>
I want to convert nested array of objects to this form because that
way searching a name will be quick if id is given. Is this the right
approach?
Getting an item from array is usually O(n). Getting an item from an object (dictionary), by the property is indexed by is O(1), so object wins... if you want to get the name by the id. However, if you are looking for an object by name, you should index by the name property. In addition, are you going to look for exact names? or names that contain something. If the search is for a part of name, then you'll still need to iterate everything O(n), and array should be fine as well.
Is there any other efficient way performance wise that can make the
search in array quicker?
It actually depends on how you are going to search, and the amount of items you are going to search through, if you are under about 50,000 and searching hy id - an object or a Map would be fine, by part of a name - an array would be ok. However, don't try to optimize before you actually have a problem, you profile it, and find that the search is to blame.
Without ramda, you could use build-in Object.fromEntries with a mapping of id and object.
const
array = [{ id: 1, name: 'Pete' }, { id: 2, name: 'John' }, { id: 3, name: 'Peter' }],
object = Object.fromEntries(array.map(o => [o.id, o]));
console.log(object[2].name);
console.log(object);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You can use Map here for better performance.
const map = new Map();
const arr = [{id: 1, name: 'Pete'}, {id: 2, name: 'John'}, {id: 3, name: 'Peter'}]
for(const {id, name} of arr){
map.set(id, name);
}
//check id exists
map.has(1) // true
//get person's name
map.get(1) //"Pete"
You could try a filter - this leaves the original array intact and returns a new array with the matches:
const arr = [{id: 1, name: 'Pete'}, {id: 2, name: 'John'}, {id: 3, name: 'Peter'}]
let filtered = arr.filter(a => a.id == 1);
console.log(filtered);

Filtering an array of objects from an array

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)

JS Search in object array by using array [duplicate]

This question already has answers here:
Filter array of objects based on another array in javascript
(10 answers)
Closed 3 years ago.
I want to remove all the object from a data array that contains the same id in an array of id. How can I achieve this task without looping it?
const id = [1, 2];
const data = [
{id: 1},
{id: 2},
{id: 3}
];
console.log(data);
You can try with Array.prototype.filter()
The filter() method creates a new array with all elements that pass the test implemented by the provided function.
and Array.prototype.includes():
The includes() method determines whether an array includes a certain value among its entries, returning true or false as appropriate.
const id = [1, 2];
const data = [
{id: 1},
{id: 2},
{id: 3}
];
var res = data.filter(i => !id.includes(i.id));
console.log(res);
let newData = data.filter(item => !id.includes(item.id));
console.log(newData);
You can use .filter() and .includes() for filtering your object.
const id = [1, 2];
let data = [
{id: 1},
{id: 2},
{id: 3}
];
data = data.filter((item) => (!id.includes(item.id)));
console.log(data);
You can use method uniqBy from lodash https://lodash.com/docs/4.17.11#uniqBy
const uniqArray = _.uniqBy([{ 'id': 1 }, { 'id': 2 }, { 'id': 1 }], 'id');
console.log(uniqArray)
<script src="https://cdnjs.cloudflare.com/ajax/libs/lodash.js/4.17.11/lodash.js"></script>

Select objects from an array of objects with an array of ids javascript

say I have a list of objects like so.
const list = [{id: 1, name: "foo"}, {id: 2, name: "bar"}, {id: 3, name: "baz"}]
And then I have a list of items I'd like to find in said list.
const ids = [1, 3]
how can I return an array of objects that match the ids found in ids from list using javascript?
heres an example of the return I'd like to see given I have [1, 3].
-> [{id: 1, name: "foo"}, {id: 3, name: "baz"}]
Thanks
- Josh
You can do it via filter method, which returns new array of items, based on condition you wrote inside. I also recommend to use includes method to check, whether your array of ids has such item:
const list = [{id: 1, name: "foo"}, {id: 2, name: "bar"}, {id: 3, name: "baz"}];
const ids = [1, 3];
const newArr = list.filter(item => ids.includes(item.id));
console.log(newArr);
You can do it with map and find:
const list = [{id: 1, name: "foo"}, {id: 2, name: "bar"}, {id: 3, name: "baz"}];
const ids = [1, 3];
const newArr = ids.map(i => list.find(({id}) => i === id));
console.log(newArr);

Merge two map objects and return custom objects javascript

I have two arrays
let a1 = [{id: 1, name: "terror"}, {id: 2, name: "comics"}, {id: 3, name: "suspense"}]
let a2 = [{id: 1, name: "terror"}, {id: 3, name: "suspense"}]
I need to compare these arrays against each other and come out with something like this:
[{id: 1, name: "terror", selected: true}, {id: 2, name: "comics", selected: false}, {id: 3, name: "suspense", selected: true}]
I tried using filter below, but it didn't work, what should I do?
a2.filter(data => {
return a1.find(value => {
let x = data.id === value.id ? {
id: value.id,
text: value.name,
selected: true
} : {
id: data.id,
text: data.name,
selected: false
}
})
})
You shouldn't use filter because you need an output array that has the same number of items you started with - use map instead, to create a new array which has the same number of elements as the original array, only transformed.
Since it looks like a2 doesn't have any new information, and is only useful by showing the existence or abscence of some objects, a method with low complexity would be to map a2 to a Set of ids, and then generate the new objects by iterating over a1 and checking whether their ids are in the Set:
let a1 = [{id: 1, name: "terror"}, {id: 2, name: "comics"}, {id: 3, name: "suspense"}]
let a2 = [{id: 1, name: "terror"}, {id: 3, name: "suspense"}]
const a2IDs = new Set(a2.map(({ id }) => id));
const output = a1.map((item) => ({ ...item, selected: a2IDs.has(item.id) }));
console.log(output);
It would be possible to fix up your code so that it works, changing .filter to .map and using .find as you are, but it'll have greater complexity because it'll have to iterate over items in a2 each time (Set lookups by comparison are O(1)).

Categories