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
Related
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);
I have a two arrays, and I want to match their ID values and then get the index of that id in the second array. I know this sounds simple but I'm super new to the syntax, and I'm having a hard time picturing what this should look like. can anyone model that in simple terms?
example functionality:
var array1 = { id:2, name: 'preston'}
array2 = {
{
id: 1
name: 'john'
},
{
id: 2
name: 'bob'
}
Expected behavior
where both ids = 2, give index of array2.
returns 1
can anyone show me?
You can use findIndex on array2
Try this:
var array1 = {
id: 2,
name: 'preston'
}
var array2 = [{
id: 1,
name: 'john'
},
{
id: 2,
name: 'bob'
}
]
console.log(array2.findIndex(item => item.id === array1.id))
Or use indexOf with map if you want support for IE as well without polyfills.
var array1 = {
id: 2,
name: 'preston'
}
var array2 = [{
id: 1,
name: 'john'
},
{
id: 2,
name: 'bob'
}
]
console.log(array2.map(item => item.id).indexOf(array1.id))
Iterate over each item in array1 using forEach(). Find each item's index in array2 using findIndex().
var array1 = [{id:2, name: "preston"}];
var array2 = [{id: 1, name: "john" }, {id: 2, name: "bob" }];
array1.forEach(item => {
let index = array2.findIndex(obj => obj.id === item.id);
console.log(index);
});
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)).
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);
Given a JS array containing many objects which all contain arrays:
var data = [
{id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]},
{id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]},
{id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];
How do I efficiently extract the inner most array (pages) values into an array?
var dataArray = [
{url: "www.abc.com", title: "abc"},
{url: "www.123.com", title: "123"},
{url: "www.xyz.com", title: "xyz"}
]
The easiest way to do this is to use Array#map like so:
var dataArray = data.map(function(o){return o.pages});
If pages is an array of objects (not a single object), this will result in an array of arrays, which you will need to flatten out for example using Array#reduce:
dataArray = dataArray.reduce(function(a,b){return a.concat(b)}, []);
You are looking for a flatMap
var data = [
{id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]},
{id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]},
{id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];
const concat = (xs, ys) => xs.concat(ys);
const prop = x => y => y[x];
const flatMap = (f, xs) => xs.map(f).reduce(concat, []);
console.log(
flatMap(prop('pages'), data)
);
If by "efficiently" you actually mean "concisely", then
[].concat(...data.map(elt => elt.pages))
The data.map will result in an array of pages arrays. The [].concat(... then passes all the pages arrays as parameters to concat, which will combine all of their elements into a single array.
If you are programming in ES5, the equivalent would be
Array.prototype.concat.apply([], data.map(function(elt) { return elt.pages; }))
Here's a working example on how to achieve what you want:
var data = [
{id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}, {url:"www.google.com", title: "Google"}]},
{id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]},
{id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];
var arr = Array();
var arr2 = Array();
// You can either iterate it like this:
for (var i = 0; i < data.length; i++) {
// If you only want the first page in your result, do:
// arr.push(data[i].pages[0]);
// If you want all pages in your result, you can iterate the pages too:
for (var a = 0; a < data[i].pages.length; a++) {
arr.push(data[i].pages[a]);
}
}
// Or use the array map method as suggested dtkaias
// (careful: will only work on arrays, not objects!)
//arr2 = data.map(function (o) { return o.pages[0]; });
// Or, for all pages in the array:
arr2 = [].concat(...data.map(function (o) { return o.pages; }));
console.log(arr);
console.log(arr2);
// Returns 2x [Object { url="www.abc.com", title="abc"}, Object { url="www.123.com", title="123"}, Object { url="www.xyz.com", title="xyz"}]
use array map() & reduce() method :
var data = [
{id: 1, name: "Fred", pages:[{url:"www.abc.com", title: "abc"}]},
{id: 2, name: "Wilma", pages:[{url:"www.123.com", title: "123"}]},
{id: 3, name: "Pebbles", pages:[{url:"www.xyz.com", title: "xyz"}]}
];
var dataArray = data.map(function(item) {
return item.pages;
});
dataArray = dataArray.reduce(function(a,b) {
return a.concat(b);
}, []);
console.log(dataArray);