How to extract multiple columns from a two dimension array? - javascript

Could I have some guidance on how to extract multiple columns from a two-dimensional array like the below using JavaScript?
Array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
];
the simple methods I've seen so far using forEach or map will allow extraction of ONE column at a time, is there a way to nest it somehow to extract whichever column index one desire?
Let's say the desire output column is 1,2 and 4.
Output = [
[1, 2, 4],
[5, 6, 8],
[9,10,12],
];
EDIT:
Another problem I need to resolve is how to remove a row if it's Array[i][1]=0 or empty.
Let say we have extra array elements...
Array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
[13,0,15,16],
[17, ,19,20],
[21,22,23,24],
];
The desired output is now...
Output = [
[1, 2, 4],
[5, 6, 8],
[9,10,12],
[21,22,24],
];

You can .map() each row in arr to a new array which you can obtain by using an inner .map() on an array of columns/indexes which you wish to obtain. The inner map will map each index to its associated value from the row, giving you the values at each column for each row.
See example below:
const arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
];
const cols = [1, 2, 4];
const res = arr.map(r => cols.map(i => r[i-1]));
console.log(res);
Further details:
As you mentioned the first map exposes each inner array inside of arr to the inner mapping function:
cols.map(i => r[i-1])
This mapping function will loop through the indexes defined inside of cols and transform them into a new value. For example, say you're r is the second array:
[5, 6, 7, 8]
Performing cols.map(...) will loop over each element (denoted by i in the callback function) in [1, 2, 4]. For each element, we "transform" it into a new element:
i = 1
r = [5, 6, 7, 8]
new value: r[1-1] = 5
Next iteration we look at the next value in cols:
i = 2
r = [5, 6, 7, 8]
new value: r[2-1] = 6
Lastly, we look at the final value in cols:
i = 4
r = [5, 6, 7, 8]
new value: r[4-1] = 8
So the mapping function produces a new array which transforms the values from cols [1, 2, 4], into the values at those indexes in the current row to be [5, 6, 8]. This occurs for each inner array / row, producing the final result.
EDIT
As per your edit, you can apply the same logic from above to get your arrays with only the columns you desire. Once you have done that you can use .filter() to keep only the rows which have a truthy value in the second column. Keeping all the arrays with truthy values in the second column will remove the arrays with non-truthy values in the second column (falsy values) from your resulting array. 0 and undefined are both flasy values, so they are not kept.
See example below:
const arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
[13,0,15,16],
[17, ,19,20],
[21,22,23,24],
]
const cols = [1, 2, 4];
const col = 2;
const res = arr.filter(r => r[col-1]).map(r => cols.map(i => r[i-1]));
console.log(res);
If you have multiple columns you want to ignore, you can use .every() to ensure each (ie: every) column contains a truthy value. If they all do, then .every() will return true, keeping the column, otherwise, it will return false, removing the column:
const arr = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
[13,0,15,16],
[ ,17,19,20],
[21,22,23,24],
]
const cols = [1, 2, 4];
const col = [1, 2];
const res = arr.filter(r => col.every(c => r[c-1])).map(r => cols.map(i => r[i-1]));
console.log(res);

You can approach it the below given way. The solution is using the index parameter available in filter method .
Array.filter(currElem,index,array)
Since array is 0-indexed ,so I created the array with index you want in the data as [0,1,3] . You need to pass the data array and index array to the function .
var array = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9,10,11,12],
];
var arrIndex = [0,1,3];
function extractData(arr,indexArr) {
return arr.map(obj => {
return obj.filter((ob,index) => {
if(indexArr.includes(index)){return ob}
})
})
}
console.log(extractData(array,arrIndex));

Related

Why is the splice function removing items from the beginning, not the end here? (Javascript)

I'm trying to write a function in Javascript that accepts a nested array and number as two arguments and returns a new nested array with the last couple items removed in each inside array as indicated by the number argument.
For example:
*/ removeColumns([[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4],
[1, 2, 3, 4]], 2);
=> [[1, 2],
[1, 2],
[1, 2],
[1, 2]]
*/
I am attaching the code have written so far. This gives me a return of [[3, 4], [3, 4]. I thought the splice function always removes array elements after the provided index but here it seems to be removing elements before the index. What am I doing wrong here?
const removeColumns = (originalGrid, numColumns) => {
for (let i = 0; i < originalGrid.length; i++) {
console.log(originalGrid[i].splice(originalGrid.length - numColumns, numColumns))
console.log(originalGrid[i])
}
return originalGrid
}
let originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
console.log(removeColumns(originalGrid, 2))
I think that should fix your issue:
originalGrid[i].length - numColumns, numColumns)
In your example
let originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
console.log(originalGrid.length) //2
console.log(originalGrid[0].length) //4
console.log(originalGrid[1].length) //4
So in the loop don't forget to add the index:
console.log(originalGrid[i].splice(originalGrid[i].length - numColumns, numColumns))
Write a filter function. Then, you can choose which column "section" to include.
const originalGrid = [
[1, 2, 3, 4],
[1, 2, 3, 4]
];
const filter = (data, from, to) => data.map(a => a.splice(from, to));
console.log(filter(originalGrid, 0, 2));

How do I check if a Javascript array contains all the other elements of another array

If I have one array:
let x= [0,1,2,3,5]
And I have an array with several subarrays:
let winningIndices = [[0, 1, 2], [6, 7, 8], [0, 3, 6], [2, 5, 8], [0, 4, 8], [2, 4, 6]]
How can I check if array x contains all of the elements of any one subarray.
In other words, how can I check if array x has combinations of either the numbers 0,1,2 or 6,7,8...
Thanks in advance
"How can I check if array x contains all of the elements of any one subarray."
Here's the most straightforward functional interpretation.
const won = winningIndices.some(indices=>
indices.every(
item=>x.includes(item)
)
)
This could be an option. If you'd like to remove xIncludesItem key from result, just map it again.
const winningIndices = [
[0, 1, 2],
[6, 7, 8],
[0, 3, 6],
[2, 5, 8],
[0, 4, 8],
[2, 4, 6]
];
const x = [0, 1, 2, 3, 5];
const result = winningIndices
.map((item) => {
const xIncludesItem = item
.map((i) => x.includes(i))
.every(includes => includes);
return { item, xIncludesItem };
})
.filter(result => result.xIncludesItem);
console.log(result);
Array.includes is much slower than Set.has. A slightly more performant solution based on Ted Brownlow's solution would be:
const setX = new Set(x);
const won = winningIndices.some(indices=>
indices.every(
item=>setX.has(item)
)
)

How can I convert multidimensional array into 2 dimensions array?

Given multidimensional array (of any size and depth):
const multidimensionalArray = [1, [2, [3, [4, [5]]]], [6], [7, [8], [9]]];
I need to convert it into 2 dimensions array following example below (the idea is that each nested value should be converted into an array of all parents + this value).
Expected 2 dimensions array :
const twoDimensionsArray = [
[1],
[1, 2],
[1, 2, 3],
[1, 2, 3, 4],
[1, 2, 3, 4, 5],
[1, 6],
[1, 7],
[1, 7, 8],
[1, 7, 9],
];
Could you please help me to solve the problem?
A recursive call for each nested array ought to do the trick.
NOTE: The following may not be complete for your use case - your data needs to be in a specific order for this to work - but I think this should be clean enough as an example:
const customFlatten = (arr, parents = [], output = []) => {
for (const item of arr) {
// If not an array...
if (!Array.isArray(item)) {
parents.push(item) // update parents for recursive calls
output.push(parents.slice(0)) // add entry to output (copy of _parents)
// If an array...
} else {
customFlatten(item, parents.slice(0), output) // recursive call
}
}
return output
}
console.log(customFlatten([1, [2, [3, [4, [5]]]], [6], [7, [8], [9]]]))

Assigning key's to array objects

I'm trying to solve this problem. Essentially, I have a array of keys, and an array of values within objects, and I want those values to have keys.
Below is my best attempt so far - usually use python so this is a bit confusing for me.
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
var result = [];
for (arr in selection) {
numbers.forEach(function (k, i) {
result[k] = arr[i]
})
};
console.log(result);
The output I'm looking for is like this,
results = [{3:1,4:2,5:3,6:4}, {..},..]
Love some pointers to getting the right output.
Note. This is for google appscript! So can't use certain javascript functions (MAP I think doesn't work, unsure of reduce).
Cheers!
Use map on selection and Object.assign
var numbers = [3, 4, 5, 6];
var selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4]
];
var result = selection.map(arr =>
Object.assign({}, ...arr.map((x, i) => ({ [numbers[i]]: x })))
);
console.log(result);
Create a separate function which take keys and values as arguments and convert it into object using reduce(). Then apply map() on selections and make an object for each subarray using that function
var numbers = [3, 4, 5,6]
var selection = [[1, 2, 3, 4], [6, 5, 4, 3], [2, 9, 4]]
function makeObject(keys, values){
return keys.reduce((obj, key, i) => ({...obj, [key]: values[i]}),{});
}
const res = selection.map(x => makeObject(numbers, x));
console.log(res)
Create a new object from scratch for each number array:
const selection = [
[1, 2, 3, 4],
[6, 5, 4, 3],
[2, 9, 4],
];
function objMaker(numarr) {
const numbers = [3, 4, 5, 6];
numarr.forEach((num, i) => (this[numbers[i]] = num));
}
console.info(selection.map(numarr => new objMaker(numarr)));

Convert an Array to unique values only while maintaining the correct sequence

I have the following code:
function uniteUnique(arr) {
//Create a single Array of value
arr = arguments[0].concat(arguments[1], arguments[2]);
//Reduce the Array to unique values only
arr = arr.reduce((pre, curr) => {
//Some function to reduce values
});
return arr;
}
uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
The goal is to produce a single Array containing only unique values while maintaining the order.
Currently it returns:
[1, 3, 2, 5, 2, 1, 4, 2, 1]
I'm wanting to reduce this to:
[1, 3, 2, 5, 4]
You can use Set for that:
function uniteUnique(...args) {
return [...new Set([].concat(...args))];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
It maintains insertion order, and by nature only contains unique values.
In ES5 you could do it by maintaining the used values as properties of a temporary object, while building the result array:
function uniteUnique(/* args */) {
return [].concat.apply([], arguments).reduce(function (acc, v) {
if (!acc[0][v]) acc[0][v] = acc[1].push(v); // assigns new length, i.e. > 0
return acc;
}, [ Object.create(null), [] ])[1];
}
var u = uniteUnique([1, 3, 2], [5, 2, 1, 4], [2, 1]);
console.log(u);
You can use the Set object since it already keeps your values unique in one object:
const mySet = new Set([1, 3, 2, 5, 2, 1, 4, 2, 1]);
// returns: Set { 1, 3, 4, 5 };
const arrayUniques = [...mySet];
console.log(arrayUniques);
// returns: [1, 3, 4, 5];

Categories

Resources