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);
Related
Trying to convert an array of objects to a single object and the array I have is similar to the following;
const array = [{id: '1', name: 'First'}, {id: '2', name: 'Second'}];
Expected output:
{'first': 1, 'second': 2}
Additionally, I want to change the casing of all values to lower case. Can assume that there are no spaces in between for the values for names. And all the ids are numbers.
Performance-wise, is there a better approach than this?
const array = [{id: '1', name: 'First'}, {id: '2', name: 'Second'}];
console.log(array);
const result = array.reduce((accumulator, value) => {return {...accumulator, [value.name.toLowerCase()]: Number(value.id)}}, {});
console.log(result);
A simple for ... of (or similar) will likely be most performant as it has no overhead of function calls. For example:
const array = [
{id: '1', name: 'First'},
{id: '2', name: 'Second'}
];
let result = {};
for (o of array) {
result[o.name.toLowerCase()] = parseInt(o.id);
}
console.log(result);
I think using a standard loop (for or while) would be the most efficient performance wise since it doesn't come with any additional stuff like map,reduce,sort do.
You could create entries and generate an object from it.
const
array = [{ id: '1', name: 'First' }, { id: '2', name: 'Second' }],
object = Object.fromEntries(array.map(({ id, name }) => [name.toLowerCase(), +id]));
console.log(object);
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 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);
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
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();