Reputation: 13185
If I have an array containing objects, where each object has an id property, I can find an index using:
data.findIndex(x=>x.id === newData.id);
But what if data was an array of array of objects? Is there a nice way of getting the two indexes for this data structure? So data.findIndex
would return i
and j
in some convenient form.
Upvotes: 2
Views: 5456
Reputation: 193258
This is my take on a recursive find index based on Array.prototype.reduce()
that can handle multiple levels of nesting:
const recursiveFindIndex = (data, id) =>
data.reduce((indexes, item, index) => {
let subIndex;
Array.isArray(item) && (subIndex = recursiveFindIndex(item, id));
if (subIndex && subIndex.length) {
return indexes.concat([index], subIndex);
}
item.id === id && (indexes.push(index));
return indexes;
}, []);
const data = [
{ id: 0 },
[{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
[{ id: 6 }, { id: 7 }, { id: 8 }, { id: 9 }, [
{ id: 10 }, { id: 11 }, { id: 12 }, { id: 13 }, { id: 14 }]
]
];
console.log('id: 3', recursiveFindIndex(data, 0));
console.log('id: 3', recursiveFindIndex(data, 3));
console.log('id: 6', recursiveFindIndex(data, 8));
console.log('id: 12', recursiveFindIndex(data, 12));
console.log('id: 3', recursiveFindIndex(data, 20));
And a more general purpose performant (it will stop the search and return as soon as a match is found) version using a for loop:
const recursiveFindIndex = (arr, predicate) => {
let subIndex;
for(let i = 0; i < arr.length; i++) {
if(Array.isArray(arr[i])) {
subIndex = recursiveFindIndex(arr[i], predicate);
if(subIndex !== -1) {
return [i].concat(subIndex);
}
} else if(predicate(arr[i])) {
return [i];
}
}
return -1;
};
const data = [
{ id: 0 },
[{ id: 1 }, { id: 2 }, { id: 3 }, { id: 4 }, { id: 5 }],
[{ id: 6 }, { id: 7 }, { id: 8 }, { id: 9 }, [
{ id: 10 }, { id: 11 }, { id: 12 }, { id: 13 }, { id: 14 }]
]
];
console.log('id: 0', recursiveFindIndex(data, (item) => item.id === 0));
console.log('id: 3', recursiveFindIndex(data, (item) => item.id === 3));
console.log('id: 6', recursiveFindIndex(data, (item) => item.id === 8));
console.log('id: 12', recursiveFindIndex(data, (item) => item.id === 12));
console.log('id: 20', recursiveFindIndex(data, (item) => item.id === 20));
Upvotes: 1
Reputation: 24955
You can use Array.includes
inside findIndex
if its an array of values.
var data = [
[1,2,3],
[4,5,6],
[7,8,9]
]
var searchParam = 8;
var index = data.findIndex(x=>x.includes(searchParam))
console.log(index)
If its an array of objects of further level of array, you can use recursion.
var data = [
[{id: 1},{id: 2},{id: 3}],
[{id: 4},{id: 5},{id: 6}],
[{id: 7},{id: 8},{id: 9}]
]
var searchValue = 8;
var index = data.findIndex(x=>{
return searchInObject(x, searchValue);
})
function searchInObject(obj, searchValue){
var _s = JSON.stringify(obj);
if(_s.indexOf(searchValue)>-1){
if(Array.isArray(obj)){
return obj.some(function(o){
if(searchInObject(o, searchValue)) return true;
});
}
else if(typeof(obj) === 'object'){
for(var k in obj){
if(searchInObject(obj[k], searchValue)) return true;
}
}
else{
if(obj === searchValue) return true;
}
}
}
console.log(index)
Upvotes: 3
Reputation: 36995
Another one using reduce
:
const data = [
[{ id : 1}, { id: 4 }],
[{ id :2 }, { id : 3}]
]
const findIJ = ( data, id ) =>
data.reduce( (p, c, i) => {
let j = c.findIndex( x => x.id === id );
if( j > - 1){
p = { i, j }
}
return p;
}, { i : -1, j : -1 });
https://jsfiddle.net/05cubh2b/
Upvotes: 0
Reputation: 27225
So, something like this?
It's probably not the most elegant solution, but it works:
const newData = { id: 1 };
const data = [[{id: 0}, {id: 1}], [{id: 2}, {id: 3}]];
data.reduce((res, x, i) => {
let j = x.findIndex(y => y.id === newData.id);
if (~j) {
return [i, j];
}
return res;
}, [-1, -1]);
Upvotes: 0