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.
6 Answers 6
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; }
Comments
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);
Comments
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)
Comments
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)
Comments
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);
Comments
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))));
15 Comments
0 or null or NaN etc. Just return the includes() statementfilter() is not correct as it assumes all values are truthy/falsy. You are misunderstanding the whole point. No need to be rude!! All my comments were constructive not insultingbucket called empty and had all the values mentioned in the above comment. On that occasion i would use the second way because it is more efficient (returned the same output for all those cases check the numbers and boolean examples above). If you can't understand this then that is no problem. So bottom-line this is a great answer (if you can see it).
Array.prototype.map.