Baz
Baz

Reputation: 13185

Find index in two dimensional array

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

Answers (4)

Ori Drori
Ori Drori

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

Rajesh
Rajesh

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

pawel
pawel

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

nils
nils

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

Related Questions