combining "columns" in multiple arrays - javascript

I have an array of arrays:
var arr = [
[0, 3, 3],
[0, 4, 3],
[1, 3, 4],
[1, 4, 4]
];
I want to create a new array that combines the contents of each index of the inner arrays. For example, the first elements at index 0 of each of the inner arrays are 0, 0, 1, and 1. I want to create a new array that combines those elements so that I end up with [0, 1] (I don't want duplicates in the new array). The next "column" is 3, 4, 3, and 4. So I'd want an array of [3, 4].
The end result I want is
[
[0, 1],
[3, 4],
[3, 4]
]
I can't quite figure out how to do this.

May not be the most efficient, but does meet you cryptic requirements.
var arr = [
[0, 3, 3],
[0, 4, 3],
[1, 3, 4],
[1, 4, 4]
];
const unique = (myArray) => [...new Set(myArray)];
let x, y,
tarr = [], // temp array
farr = []; // final array
for (x=0; x<arr.length; x++) {
tarr.length = 0;
for (y=0; y<arr[x].length; y++) {
tarr.push(arr[y][x])
}
farr.push( unique(tarr) );
}
console.log(farr.join('\n'));

Here another solution.
const result = (arr) => {
let index = 0;
const min = Math.min(...arr.map(r => r.length)) // get min length
const grid = [];
while (index < min) { // loop with min
let s = new Set(); // using set to keep unique values
arr.forEach(r => s.add(r[index])); // pick value
grid.push([...s]); // get array from set
index++;
}
return grid
}
const array = [ [0, 3, 3], [0, 4, 3], [1, 3, 4], [1, 4, 4] ];
console.log(result(array))

Related

How To get the values of object sorted with keys in distinct arrays?

Given an array of arrays, I want to get the averages of each subarray, and then output which subarrays have the same average. The output will not repeat the subarrays, but just the indices where they occur in the input array.
So for this input:
[
[3, 3, 4, 2], // index 0: average = 3
[4, 4], // index 1: average = 4
[4, 0, 3, 3], // index 2: average = 2.5
[2, 3], // index 3: average = 2.5
[3, 3, 3], // index 4: average = 3
];
The expected output is:
[[0, 4], [1], [2, 3]]
...because the subarrays at indices 0 and 4 have the same average, while the subarray at index 1 has an average that is not shared by another subarray, and finally the subarrays at indices 2 and 3 have the same average.
I completed the function as we see below, and the averages are calculated correctly, but I can't get the values of the object sorted with keys in distinct arrays...
function solution(a) {
let b = [];
let entier = {};
a.filter((elt, cle) => {
let s = a[cle].reduce((prevalue, curvalue) => prevalue + curvalue, 0);
b[cle] = s / a[cle].length;
//console.log(s/a[cle].length)
entier[cle] = s / a[cle].length;
});
console.log(entier);
let arrNew = Object.entries(entier);
console.log(arrNew);
}
let a = [
[3, 3, 4, 2],
[4, 4],
[4, 0, 3, 3],
[2, 3],
[3, 3, 3],
];
solution(a); // [[0, 4], [1], [2, 3]]
How can I make my code work?
With this:
entier[cle] = s / a[cle].length;
...you are assigning the average as a value associated with the current index as the key. But you need the opposite. You'll want to group by the average, so that must be the key, and the index must be the value (but as an array).
So change that to:
(entier["x" + (s / a[cle].length)] ??= []).push(cle);
The "x" is to ensure that the key is not an integer as then different rules apply for the ordering of that key in the object. By prepending this "x", we ensure that keys are ordered in the order they are created.
The ??= assignment ensures that the property is initialised as an array when it didn't exist yet.
The second correction is here: Object.entries should be Object.values as you are no longer interested in those "x" keys.
function solution(a) {
let entier = {};
a.filter((elt, cle) => {
let s = a[cle].reduce((prevalue, curvalue) => prevalue + curvalue, 0);
(entier["x" + (s / a[cle].length)] ??= []).push(cle);
});
let arrNew = Object.values(entier);
console.log(arrNew);
}
let a = [
[3, 3, 4, 2], // 0: 3
[4, 4], // 1: 4
[4, 0, 3, 3], // 2: 2.5
[2, 3], // 3: 2.5
[3, 3, 3], // 4: 3
];
solution(a); // [[0, 4], [1], [2, 3]]

Extract subarray from a multidimensional array and mutate the original array

I want to extract a subarray from a multidimensional array and have the original array be mutated so it no longer contains the extracted subarray
If I have a multidimensional array called originalArray
I can extract a subarray from a list of header indices
function newArrCols(arrayofarray, indexlist) {
return arrayofarray.map(function (array) {
return indexlist.map(function (idx) {
return array[idx];
});
});
}
So If:
idxList = [1,2,5,7]
subArray = newArrCols(originalArray, idxList)
Know I have to delete the subArray from the originalArray
//Remove columns from original arr w.r.t headeridx
for (var i = 0; i <= idxList.length - 1; i++) {
originalArray.map(a => a.splice(idxList[i], 1));
}
Is there a way to do this in a single process I would like to skip the deleting part
Thanks
EDIT:
Create a temporary empty array that will hold the items of the originalArray that aren't included in the idxList
let tempArray = [];
Create the subArray and populate the tempArray using Array.reduce():
let subArray = originalArray.reduce((accumulator, current, index) => {
if (idxList.includes(index)) {
//if the current index is included in the idxList array,
//push the current value to the accumulator
accumulator.push(current);
} else {
//push the current value to the `tempArray`.
tempArray.push(current)
}
return accumulator;
}, []);
Replace the originalArray with a deep clone of the tempArray
originalArray = JSON.parse(JSON.stringify(tempArray));
Working snippet below.
let originalArray = [
[0, 0, 0, 0],
[1, 1, 1, 1],
[2, 2, 2, 2],
[3, 3, 3, 3],
[4, 4, 4, 4],
[5, 5, 5, 5],
[6, 6, 6, 6],
[7, 7, 7, 7],
];
let idxList = [1, 2, 5, 7];
let tempArray = [];
//Can also be written in a one line arrow function
let subArray = originalArray.reduce((a, c, i) => (idxList.includes(i) ? a.push(c) : tempArray.push(c), a), []);
originalArray = JSON.parse(JSON.stringify(tempArray));
tempArray = [];
console.log({
subArray: JSON.stringify(subArray)
});
console.log({
originalArrayAfter: JSON.stringify(originalArray)
});

Javascript: How to find difference for two number arrays

I need to create a new array made up of unique elements from two separate arrays.
I have converted both arrays into a single array and then converted this into an object to check the frequency of the elements. If the value of an object property is 1 (making it a unique property), I want to return it to an array (minus the value). Is there a straightforward way to achieve this?
Edits: Moved result outside for loop. Expected output should be [4]
function diffArray(arr1, arr2) {
var finalArr = [];
var countObj = {};
var newArr = [...arr1, ...arr2];
for (var i = 0; i < newArr.length; i++) {
if (!countObj[newArr[i]]) countObj[newArr[i]] = 0;
++countObj[newArr[i]];
}
for (var key in countObj) {
if (countObj[key] === 1) {
finalArr.push(key);
}
} return finalArr;
}
diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]);
If I understand correctly, you're wanting to find the difference between arr1 and arr2, and returns that difference (if any) as a new array of items (that are distinct in either array).
There are a number of ways this can be achieved. One approach is as follows:
function diffArray(arr1, arr2) {
const result = [];
const combination = [...arr1, ...arr2];
/* Obtain set of unique values from each array */
const set1 = new Set(arr1);
const set2 = new Set(arr2);
for(const item of combination) {
/* Iterate combined array, adding values to result that aren't
present in both arrays (ie exist in one or the other, "difference") */
if(!(set1.has(item) && set2.has(item))) {
result.push(item);
}
}
return result;
}
console.log(diffArray([1, 2, 3, 5], [1, 2, 3, 4, 5]), " should be [4]");
console.log(diffArray([1, 2, 3, 5, 8], [1, 2, 3, 5]), " should be [8]");
console.log(diffArray([1, 2, 3, 5, 8], [1, 2, 3, 5, 9]), " should be [8, 9]");
console.log(diffArray([1, 2], [1, 2]), " should be []");

array index selection like in numpy but in javascript

I have a 3x3 array:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
and want to get the first 2x2 block of it (or any other 2x2 block):
[[0,1],
[3,4]]
with numpy I would have written:
my_array = np.arange(9).reshape((3,3))
my_array[:2, :2]
to get the correct result.
I tried in javascript:
my_array.slice(0, 2).slice(0, 2);
but the second slice affects the first dimension, doing nothing.
Am I doomed to use for loop or is there some new ES6 syntax that would make my life simpler?
Could use a combination of Array.slice and Array.map:
const input = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
const result = input.slice(0, 2).map(arr => arr.slice(0, 2));
console.log(result);
You can use .map() and .slice() methods:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
var result = my_array.slice(0, 2).map(a => a.slice(0, 2));
console.log(result);
.as-console-wrapper { max-height: 100% !important; top: 0; }
You could take objects for the indices and for the length of the wanted sub arrays.. Then slice and map the sliced sub arrays.
var array = [[0, 1, 2], [3, 4, 5], [6, 7, 8]],
length = { x: 2, y: 2 },
indices = { i: 0, j: 0 },
result = array.slice(indices.i, indices.i + length.x).map(a => a.slice(indices.j, indices.j + length.y));
console.log(result);
It dont seems to a 3x# array , it is just array of arrays.
You can first use slice to get an array of only first two elements that is
[[0, 1, 2],[3, 4, 5]]
then use reduce to return a new array & inside it get only the first two values
var my_array = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
let x = my_array.slice(0, 2).reduce(function(acc, curr) {
acc.push(curr.slice(0, 2))
return acc;
}, [])
console.log(x)
const input = [
[0, 1, 2],
[3, 4, 5],
[6, 7, 8]
];
let result =[]
input.forEach(([a, b], index) => {if(index < 2) result.push([a, b])})
console.log(result);
If you are going to work a lot with matrices, then you should check out math.js.
Try the following:
var my_array = [[0,1,2],
[3,4,5],
[6,7,8]];
var matrix = math.matrix(my_array);
var subset = matrix.subset(math.index([0, 1], [0, 1]));
Working example.

Fastest way to Reduce and concat (or deep flatten) arrays of arrays

As input, I receive two types of arrays of arrays made of x and y coordinates that represent polygon and multipolygon geometries.
array1 represents coordinates of a simple polygon geometry and array2 represent a multipolygon geometry:
var array1 = [[[0 , 0], [0, 1], [0 ,2]]]
var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]]]]
Multipolygon geometry (array2) are represented by an array of arrays one level deeper than simple polygon geometry (array1).
I want to flatten those arrays in order to get those output:
if input is array1 type : array1_out = [[0, 0, 0, 1, 0, 2]]
if input is array2 type : array2_out = [[0, 0, 0, 1, 0, 2], [1, 0, 1, 1, 1, 2]]
My function is the following:
for (i=0; i < array_input.length; i++){
var array_concat = array_input[i].reduce(function(a, b){
return a.concat(b);
});
}
With this function above, the output for array1 is correct but the output of array2 is the following:
[[[0, 0] ,[0, 1], [0, 2]], [1, 0], [1, 1], [1, 2]]]
Is there a function to deeply flatten those two types of arrays?
Edit: Performance really matter here as the arrays are really big
You can find a lot of helpful tools for manipulating arrays and collections in the Underscore and lodash libraries.
var arrays1 = [[[0 , 0], [0, 1], [0 ,2]]];
var array2 = [[[[0, 0] , [0, 1], [0, 2]], [[1, 0], [1, 1], [1 ,2]], ]];
var array1_out = flattenSimple(arrays1);
console.log(JSON.stringify(array1_out));
var array2_out = flattenMultiple(array2);
console.log(JSON.stringify(array2_out));
function flattenSimple(array_input) {
return _.flatten(array_input);
}
function flattenMultiple(array_input) {
array_input = array_input[0];
return array_input.map(function(a) {
return _.flatten(a);
});
}
Will produce the output you're looking for. I broke it into a flatten fn for each type, but you could use the same fn with a flag or more complex logic to know which type you're working with.
Fiddle
You can add a small wrapper for your function, that can check what type in input and a bit modify input
function getDeepLength(arr) {
for (var i = 0, cur = arr; cur[0] instanceof Array; i++, cur = cur[0]);
return i;
}
function Flatten(array_input) {
var array_concat = [];
for (i = 0; i < array_input.length; i++) {
array_concat.push(array_input[i].reduce(function(a, b) {
return a.concat(b);
}));
}
return array_concat;
}
function Wrapper(arr) {
var deep = getDeepLength(arr);
var cur = arr;
if (deep > 2) {
for (var i = deep - 2; i > 0; i--, cur = cur[0]);
}
return Flatten(cur)
}
var array1 = [
[
[0, 0],
[0, 1],
[0, 2]
]
];
var array2 = [
[
[
[0, 0],
[0, 1],
[0, 2]
],
[
[1, 0],
[1, 1],
[1, 2]
]
]
];
document.getElementById('r').innerHTML = "array1: "
+ JSON.stringify(array1)+"<br/>"
+ "flat array1: "+JSON.stringify(Wrapper(array1))+"<br/>"
+ "array2: "+JSON.stringify(array2)+"<br/>"
+ "flat array2: "+JSON.stringify(Wrapper(array2));
<div id='r'></div>

Categories