skip to Main Content

I have a two dimensional array that in turn has an object with an additional array.

I want to filter the array and return a new array with the index that matches the criteria with the object.

For example:

One array: gp[0][0].pts = [10,5,40,30,95,5,11,85];
I want to search the array and return values above or equal to 20. This would be [40, 30, 95, 85];

I want the new array to return the indexes for these, so in this case it would be [2,3,4,7]

The code below returns the correct numbers but I want the indexes instead.

Thanks in advance.

const gp = [
  [{
    "pts": [10, 5, 40, 30, 95, 5, 11, 85]
  }, {
    "pts": [2, 1, 4]
  }, {
    "pts": [14, 22, 41, 23]
  }]
];


for (let n = 0; n <= 2; n++) {
  const race = gp[0][n].pts.filter(v => +v >= 20).map(Number);
  if (race.length) {
    console.log(`race at n=${n}: ${race}`);
  };
};

5

Answers


  1. You could achieve that with the following

    1- Map each value to an object containing both value and index

    2- Filter objects with value >= 20

    3- Map back to indices

    let gp = [];
    gp[0] = [];
    gp[0][0] = {};
    gp[0][0].pts = [10, 5, 40, 30, 95, 5, 11, 85];
    
    gp[0][1] = {};
    gp[0][1].pts = [2, 1, 4];
    
    gp[0][2] = {};
    gp[0][2].pts = [14, 22, 41, 23];
    
    
    
    const filteredIndicesPerRace = {};
    
    gp[0].forEach((race, raceIndex) => {
      filteredIndicesPerRace[raceIndex] = race.pts
        .map((value, index) => ({
          value,
          index
        })) 
        .filter(obj => obj.value >= 20) 
        .map(obj => obj.index); 
    });
    
    console.log(filteredIndicesPerRace);
    Login or Signup to reply.
  2. First, map the arrays to [element, index] pairs. Then filter, then extract just the indices.

    const gp = [
      [{
        "pts": [10, 5, 40, 30, 95, 5, 11, 85]
      }, {
        "pts": [2, 1, 4]
      }, {
        "pts": [14, 22, 41, 23]
      }]
    ]
    
    gp[0].forEach(({pts}, n) => {
      let race = pts.map((e,i) => [e,i]).filter(([e]) => +e >= 20).map(([,i]) => i)
      if(race.length) console.log(`race at n=${n}: ${race}`)
    })
    Login or Signup to reply.
  3. Instead of first filtering, and then mapping, first map your "number" to a "number and index", then filter:

    const gp = [{
      pts: [10, 5, 40, 30, 95, 5, 11, 85]
    }, {
      pts: [2, 1, 4]
    }, {
      pts: [14, 22, 41, 23]
    }];
    
    
    function testOver(data, threshold) {
      return data.map(({ pts }, n) => {
        const result = pts
          .map((num, index) => ({num, index}))
          .filter(({ num }) => num >= threshold);
        
        if (result.length) {
          return { [n]: result };
        }
    
        return false;
      }).filter(Boolean);
    }
    
    console.log(testOver(gp, 20));

    Or if you know your downstream code will never need both the index and the associated value, return {n: result.map(({ index }) => index)} instead, of course.

    Alternatively, use reduce as mentioned by Alexander Nenashev

    Login or Signup to reply.
  4. If you want a performant fast solution, use Array#reduce() and collect indices without intermediate arrays (waste of time & space):

    const gp = [
      [{
        "pts": [10, 5, 40, 30, 95, 5, 11, 85]
      }, {
        "pts": [2, 1, 4]
      }, {
        "pts": [14, 22, 41, 23]
      }]
    ];
    
    
    for (let n = 0; n < gp[0].length; n++) {
      const race = gp[0][n].pts.reduce((r, v, i) => (v >= 20 && r.push(i), r), []);
      if (race.length) {
        console.log(`race at n=${n}: ${race}`);
      };
    };

    And a benchmark:

    ` Chrome/124
    ------------------------------------------------------------------------------------------
    >                    n=3        |       n=30        |       n=300       |      n=3000     
    Alexander      ■ 1.00x x10m 370 | ■ 1.00x   x1m 382 | ■ 1.00x x100k 371 | ■ 1.00x x10k 359
    Andrew Parks     3.59x  x1m 133 |   3.66x x100k 140 |   3.99x  x10k 148 |   4.46x  x1k 160
    ------------------------------------------------------------------------------------------
    https://github.com/silentmantra/benchmark `
    
    const $chunk = [{
        "pts": [10, 5, 40, 30, 95, 5, 11, 85]
      }, {
        "pts": [2, 1, 4]
      }, {
        "pts": [14, 22, 41, 23]
      }];
    
    const $input = [];
    const gp = [$input];
    
    // @benchmark Andrew Parks
    gp[0].forEach(({pts}, n) => {
      pts.map((e,i) => [e,i]).filter(([e]) => +e >= 20).map(([,i]) => i);
    })
    
    // @benchmark Alexander
    for (let n = 0; n < gp[0].length; n++) {
      gp[0][n].pts.reduce((r, v, i) => (v >= 20 && r.push(i), r), [])
    }
    
    /*@skip*/ fetch('https://cdn.jsdelivr.net/gh/silentmantra/benchmark/loader.js').then(r => r.text().then(eval));
    Login or Signup to reply.
  5. And here is another solution on the basis of Array.forEach() and Array.reduce():

    const gp = [
      [{
        "pts": [10, 5, 40, 30, 95, 5, 11, 85]
      }, {
        "pts": [2, 1, 4]
      }, {
        "pts": [14, 22, 41, 23]
      }]
    ];
    
    
    gp[0].forEach(({pts},n)=>{ 
      const race=pts.reduce((a,c,i)=>{
        if(+c>=20) a.push(i);
        return a;
      },[]);
      if (race.length) {
        console.log(`race at n=${n}: ${race}`);
      };
    });
    Login or Signup to reply.
Please signup or login to give your own answer.
Back To Top
Search