Rass_Rukh
Rass_Rukh

Reputation: 25

how to optimize multiple Array.find()

I have JSON: (It has way too many rows, but would be too long to paste whole json)

"data": {
  "rows": [
      {
          "row_no": "130",
          "sum_begin_period": "3234122.29",
          "sum_end_period": "3099063"
      },
      {
          "row_no": "150",
          "sum_begin_period": "1252394",
          "sum_end_period": "986382"
      },
      {
          "row_no": "160",
          "sum_begin_period": "1321400.28",
          "sum_end_period": "1321400"
      },
      {
          "row_no": "210",
          "sum_begin_period": "3367691.4",
          "sum_end_period": "1282444"
      },
      {
          "row_no": "220",
          "sum_begin_period": "2320199.07",
          "sum_end_period": "265000"
      },
      {
          "row_no": "260",
          "sum_begin_period": "1047492.33",
          "sum_end_period": "1017444"
      },
      {
          "row_no": "610",
          "sum_begin_period": "825495.3",
          "sum_end_period": "960385"
      }
  ]
}

I need to do some math operations for which I need values from multiple rows. How can I do that elegantly?
What I have tried till now:
with Array.find():

let ccScore;
  for(const row of finance_report){

    const satr_390_1 = finance_report.find((row) => row.row_no === "390");
    const satr_190_1 = finance_report.find((row) => row.row_no === "190");
    const satr_211_1 = finance_report.find((row) => row.row_no === "211");
    const satr_600_1 = finance_report.find((row) => row.row_no === "600");

    if (satr_600_1== 0) return 1;

    ccScore = (satr_390_1 - satr_190_1- satr_211_1) / satr_600_1;

    if (ccScore < 0.5) return 1;
    else if (ccScore >= 0.5 && ccScore < 2) return 3;
    else if (ccScore >= 2) return 5;
  }

Disadvantage of above is Array.find is being repeated way too many times.
with Array.maps(): (searching with IF statement inside a callback of .map())

 let accounting_factor;

  accounting_report.map((row) => {
    let summ = 0;
    if (row.row_no === "480") summ += parseInt(row.sum_end_period);
    if (row.row_no === "490") summ += parseInt(row.sum_end_period);

    if (row.row_no === "130") {
      accounting_factor =
        parseInt(row.sum_end_period) > parseInt(summ) ? false : true;
    }
  });

Disadvantage of above is IF being repeated.
Is there a more elegant approach which does not force me to repeat my code and enables me to extract objects(from "rows" array) with certain rows.row_no and then do operation?
P.S. If Array.reduce() can solve the issue, I would appreciate an example of it

Upvotes: 2

Views: 697

Answers (4)

Steven Spungin
Steven Spungin

Reputation: 29129

Map your data to rows using a reduction function.

const mapped = data.rows.reduce((a,v)=>{a[v.row_no]=v;return a},{})

Now your rows are indexed by row_no

mapped['100']

You can also use destructuring in your reduction. (thanks jsNOOb)

const mapped = data.rows.reduce((a,v)=>({...a, [v.row_no]: v}),{})

Upvotes: 3

Tiago Coelho
Tiago Coelho

Reputation: 5091

Use filter, includes and reduce

const wantedRowIds = [390,190,211,600];
const wantedRows = finance_report.filter(row => wantedRowIds.includes(+row.row_no));

const rowsById = wantedRows.reduce((acc,row) => ({...acc, [row.row_no]:row}),{});

Then use them like ccScore = rowsById[390] - rowsById[190] - rowsById[211] / rowsById[600];

Upvotes: 0

KooiInc
KooiInc

Reputation: 122936

Would Array.filter do the job?

const rowNrsINeed = [220, 130, 800];
const filtered = retrieveData().data.rows.filter(row => 
  rowNrsINeed.find(no => no === +row.row_no));

filtered.forEach( r => 
  console.log(`row: ${r.row_no}; sum_begin_period: ${r.sum_end_period}`) )

for (let row of filtered) {
  // ... do stuff with each found row
}

function retrieveData() {
  return {
    "data": {
      "rows": [{
          "row_no": "130",
          "sum_begin_period": "3234122.29",
          "sum_end_period": "3099063"
        },
        {
          "row_no": "150",
          "sum_begin_period": "1252394",
          "sum_end_period": "986382"
        },
        {
          "row_no": "160",
          "sum_begin_period": "1321400.28",
          "sum_end_period": "1321400"
        },
        {
          "row_no": "210",
          "sum_begin_period": "3367691.4",
          "sum_end_period": "1282444"
        },
        {
          "row_no": "220",
          "sum_begin_period": "2320199.07",
          "sum_end_period": "265000"
        },
        {
          "row_no": "260",
          "sum_begin_period": "1047492.33",
          "sum_end_period": "1017444"
        },
        {
          "row_no": "610",
          "sum_begin_period": "825495.3",
          "sum_end_period": "960385"
        }
      ]
    }
  };
}

Upvotes: 0

Karan Kaushik
Karan Kaushik

Reputation: 139

Restructure the data as follows

let rows = {}

original.data.rows.forEach(row => rows[row.row_no] = row)

// USAGE
rows[ROW_NUM].sum_end_period

You can try this out, I believe it'll be faster because a key value tuple is an indexed object and the program won't have to iterate over each element in the array.

Upvotes: 5

Related Questions