Lodash Remove objects from array by matching ids array - javascript

I have an array of objects like:
var a = [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'},
{id: 4, name: 'D'}
];
And Ids array which i want to remove from array a :
var removeItem = [1,2];
I want to remove objects from array a by matching its ids, which removeItem array contains. How can i implement with lodash.
I Checked lodash's _.remove method, but this need a specific condition to remove an item from array. But i have list of ids which i want to remove.

As you mentioned you need the _.remove method and the specific condition you mention is whether the removeItem array contains the id of the checked element of the array.
var removeElements = _.remove(a, obj => removeItem.includes(obj.id));
// you only need to assign the result if you want to do something with the removed elements.
// the a variable now holds the remaining array

You have to pass a predicate function to .remove method from lodash.
var final = _.remove(a, obj => removeItem.indexOf(obj.id) > -1);
using indexOf method.
The indexOf() method returns the first index at which a given element
can be found in the array, or -1 if it is not present.
You can do it using native javascript using filter method which accepts as parameter a callback function.
var a = [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'},
{id: 4, name: 'D'}
];
var removeItem = [1,2];
a = a.filter(function(item){
return removeItem.indexOf( item.id ) == -1;
});
console.log(a);
But filter method just creates a new array by applying a callback function.
From documentation:
The filter() method creates a new array with all elements that pass
the test implemented by the provided function.
If you want to modify the original array use splice method.
var a = [
{id: 1, name: 'A'},
{id: 2, name: 'B'},
{id: 3, name: 'C'},
{id: 4, name: 'D'}
];
var removeItem = [1,2];
removeItem.forEach(function(id){
var itemIndex = a.findIndex(i => i.id == id);
a.splice(itemIndex,1);
});
console.log(a);

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);

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);

Lodash object by Index

In lodash, how can I get an object from an array by the index at which it occurs, instead of searching for a key value.
var tv = [{id:1},{id:2}]
var data = //Desired result needs to be {id:2}
Let's take for example this collection:
var collection = [{id: 1, name: "Lorem"}, {id: 2, name: "Ipsum"}];
I will talk about two approaches, indexing and not indexing.
In general, indexing is better if you want to access many of the items, because you loop the collection once. If not, Meeseeks solution with find is the right choice.
Indexing
var byId = _.groupBy(collection, 'id');
var byName = _.groupBy(collection, 'name');
now you can reach each item by it indexed key:
console.log(byId[2]); // Object {id: 2, name: "Ipsum"}
console.log(byName.Lorem); // Object {id: 1, name: "Lorem"}
Without indexing
var item = _.find(collection, {id: 2});
console.log(item); // Object {id: 2, name: "Ipsum"}
I think what you're looking for is find
You can give it an object and it will return the matched element or undefined
Example
var arr = [ { id: 1, name: "Hello" }, { id: 2, name: "World" } ];
var data = _.find(arr, { id: 1 }); // => Object {id: 1, name: "Hello"}
var data = _.find(arr, { id: 3 }); // => undefined

How to partition array into multiple groups using Lodash?

I'm trying to find a concise way to partition an array of objects into groups of arrays based on a predicate.
var arr = [
{id: 1, val: 'a'},
{id: 1, val: 'b'},
{id: 2, val: 'c'},
{id: 3, val: 'a'}
];
//transform to below
var partitionedById = [
[{id: 1, val: 'a'}, {id: 1, val:'b'}],
[{id: 2, val: 'c'}],
[{id: 3, val: 'a'}
];
I see this question , which gives a good overview using plain JS, but I'm wondering if there's a more concise way to do this using lodash? I see the partition function but it only splits the arrays into 2 groups (need it to be 'n' number of partitions). The groupBy groups it into an object by keys, I'm looking for the same but in an array (without keys).
Is there a simpler way to maybe nest a couple lodash functions to achieve this?
You can first group by id, which will yield an object where the keys are the different values of id and the values are an array of all array items with that id, which is basically what you want (use _.values() to get just the value arrays):
// "regular" version
var partitionedById = _.values(_.groupBy(arr, 'id'));
// chained version
var partitionedById = _(arr).groupBy('id').values().value();

Categories