Jonathan Griffin
Jonathan Griffin

Reputation: 148

Javascript for loop return results to nested array

I am trying to return a selection of data from a nested array to a new nested array but the data is just being pushed into array.

var selection = [0,1,3,4];
var allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']]
var selectedProductData = []

for(var apd=0; apd<allProductData.length; apd++) {
  for(var spd=0; spd<allProductData[apd].length; spd++) {
    for(var s=0; s<selection.length; s++) {
      if(allProductData[apd].indexOf(allProductData[apd][spd]) === selection[s]) {
        selectedProductData.push(allProductData[apd][spd])
      }
    }
  }
}
console.log(selectedProductData)

This returns the following

[
  "Item1Sku","Item1Name","Item1Price","Item1Available",
  "Item2Sku","Item2Name","Item2Price","Item2Available",
  "Item3Sku","Item3Name","Item3Price","Item3Available"
]

What I want is

[
  ["Item1Sku","Item1Name","Item1Price","Item1Available"],
  ["Item2Sku","Item2Name","Item2Price","Item2Available"],
  ["Item3Sku","Item3Name","Item3Price","Item3Available"]
]

Any help with this would be great.

Upvotes: 1

Views: 685

Answers (6)

user2560539
user2560539

Reputation:

Something like the below snippet does the work you want. Additionally see:

let selection = [0,1,3,4];
let allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];
let filtered = allProductData.map(item => item.filter((val,index) => selection.includes(index)));
console.log(filtered);

There was a lot of noise about this syntax (snippet below).on comments, about the fact that the callback function in filter() having to evaluate to true. The actual words in MDN are:

Function is a predicate, to test each element of the array. Return true to keep the element, false otherwise

let selection = [0,1,3,4];
let allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];
let filtered = allProductData.map(item => 
  item.filter((val,index) => {
  if(selection.includes(index)) {
    return val;
  }
  })
);
console.log(filtered);

So here are some examples that do the exact same thing without raising an error. In all cases what is returned by .filter() is the logical true that will match the conditions in the callback function.

let selection = [0,1,3,4];
let allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];
let filtered = allProductData.map(item => 
  item.filter((val,index) => {
    if(selection.includes(index)) {
      return index > 3; // this will return only the itemXAvailability
    }
  })
);
console.log(filtered);

The above snippet could be re-written this way.

let selection = [0,1,3,4];
let allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];
let filtered = allProductData.map(item => 
  item.filter((val,index) => selection.includes(index) && index > 3)
);
console.log(filtered);

Two more examples using Boolean true, false as values of the array to test.

let selection = [0,1,3,4];
let allProductData = [[true,true, false, true, false, true], [true,true,true,true,true,true], [false,false,false,false,false,false]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => selection.includes(index) && index > 3)
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

Notice the difference in the output.

let selection = [0,1,3,4];
let allProductData = [[true,true, false, true, false, true], [true,true,true,true,true,true], [false,false,false,false,false,false]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => {
    if(selection.includes(index) && index > 3) {
      return val;
    }
    })
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

Two more examples using numbers. Output differs for value being 0.

let selection = [0,1,3,4];
let allProductData = [[1,2,3,4,5,6], [6,5,4,3,2,1], [8,8,8,8,0,8]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => selection.includes(index) && index > 3)
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

let selection = [0,1,3,4];
let allProductData = [[1,2,3,4,5,6], [6,5,4,3,2,1], [8,8,8,8,0,8]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => {
    if(selection.includes(index) && index > 3) {
      return val;
    }
    })
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

What would be the difference when using null as our value.

let selection = [0,1,3,4];
let allProductData = [[null,null,null,null,null,null], [null,null,null,null,null,null], [null,null,null,null,null,null]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => selection.includes(index) && index > 3)
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

let selection = [0,1,3,4];
let allProductData = [[null,null,null,null,null,null], [null,null,null,null,null,null], [null,null,null,null,null,null]];
let filtered = allProductData.map(item => 
  item.filter((val,index) => {
    if(selection.includes(index) && index > 3) {
      return val;
    }
    })
);
console.log(filtered);
filtered.forEach((item) => item.forEach((val) => console.log(typeof(val))));

Upvotes: 0

Sascha A.
Sascha A.

Reputation: 4616

Use array.map and array.filter for it.

var selection = [0,1,3,4];
var allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];

let result = allProductData.map(data => {
    return data.filter((el, ind) => selection.indexOf(ind)!=-1);
})

console.log(result);

Upvotes: 0

fedesc
fedesc

Reputation: 2610

Use for...of instead of i=0;i<x;i++ it's more readable and can help you with the flow.

Also you can reach each element index inside your first loop, instead of setting selection array. you would still write it only one time and spare a loop.

var allProductData = [['Item1Sku', 'Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'],['Item2Sku', 'Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'],['Item3Sku', 'Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']];
var selectedProductData = [];

for (let data of allProductData) {
  selectedProductData.push([data[0], data[1], data[3], data[4]]);
}

console.log(selectedProductData)

Upvotes: 1

Kunal Mukherjee
Kunal Mukherjee

Reputation: 5853

Use Array.prototype.reduce to reduce the array and check if each current element's index lies within the selection array or not, if it does then push it.

const selection = [0, 1, 3, 4];
const allProductData = [
  ['Item1Sku', 'Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'],
  ['Item2Sku', 'Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'],
  ['Item3Sku', 'Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']
];

const selectedProductData = allProductData.reduce((acc, curr) => {
  const filtered = curr.filter((product, idx) => selection.includes(idx));

  if (filtered.length) {
    acc.push(filtered);
  }
  return acc;
}, []);

console.log(selectedProductData);

Upvotes: 1

Mamun
Mamun

Reputation: 68933

You should create another array inside the first for loop and push the result in that array first, then push that array into the final array:

var selection = [0,1,3,4];
var allProductData = [['Item1Sku','Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku','Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku','Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']]
var selectedProductData = []

for(var apd=0; apd<allProductData.length; apd++) {
  var temp = []; // declare an array here
  for(var spd=0; spd<allProductData[apd].length; spd++) {
    for(var s=0; s<selection.length; s++) {
      if(allProductData[apd].indexOf(allProductData[apd][spd]) === selection[s]) {
        temp.push(allProductData[apd][spd]); // push the result 
      }
    }
  }
  selectedProductData.push(temp); // push the array into the final array
}
console.log(selectedProductData)

Upvotes: 0

Nina Scholz
Nina Scholz

Reputation: 386624

You could map the data and the values at the wanted index.

const
    selection = [0, 1, 3, 4],
    allProductData = [['Item1Sku', 'Item1Name', 'Item1Desc', 'Item1Price', 'Item1Available', 'Item1Margin'], ['Item2Sku', 'Item2Name', 'Item2Desc', 'Item2Price', 'Item2Available', 'Item2Margin'], ['Item3Sku', 'Item3Name', 'Item3Desc', 'Item3Price', 'Item3Available', 'Item3Margin']],
    selectedProductData = allProductData.map(values => selection.map(i => values[i]));

console.log(selectedProductData);
.as-console-wrapper { max-height: 100% !important; top: 0; }

Upvotes: 3

Related Questions