Javascript - transpose dict into array - javascript

I have a the following dict I would like to transpose:
dict = {
'column1': [1, 2, 3],
'column2': [4, 5, 6],
'column3': [7, 8, 9]
}
Into:
transposed_array = [
[1, 4, 7],
[2, 5, 8],
[3, 6, 9]
]

Here's a solution (updated for non square matrices):
var dict = {
'column1': [1, 2, 3],
'column2': [4, 5, 6],
'column3': [7, 8, 9]
}
var keys = Object.keys(dict);
var transposedMatrix = dict[keys[0]].map(function(col,i){
return keys.map(function(_,j){ return dict[keys[j]][i] })
});
Demonstration
Note that this code assumes that objects do have ordered keys, which has always been the case in all known ES implementations and is now normalized by ES6.

var dict = {
'column1': [1, 2, 3],
'column2': [4, 5, 6],
'column3': [7, 8, 9]
};
var transposed_array =[];
for (key in dict){
transposed_array.push(dict[key]);
}
console.log(transposed_array);
Demo
Updated:
var dict = {
'column1': [1, 2, 3],
'column2': [4, 5, 6],
'column3': [7, 8, 9]
};
var transposed_array =[];
for (key in dict){
transposed_array.push(dict[key]);
}
function transposeArray(array){
var newArray = [];
for(var i = 0; i < array.length; i++){
newArray.push([]);
}
for(var i = 0; i < array.length; i++){
for(var j = 0; j < array[i].length; j++){
newArray[j].push(array[i][j]);
}
}
return newArray;
}
console.log(transposeArray(transposed_array));
Demo

basically first find the shared part of the keys, then the endings, after sort reassamle the array. the result is numerical orderd if number otherwise the order is maintained.
var dict = {
'column3': [7, 8, 9],
'column2': [4, 5, 6],
'column1': [1, 2, 3]
},
keys = Object.keys(dict),
samePart = keys.reduce(function (a, b) {
var i = 0, l = Math.min(a.length, b.length);
while (i < l && a[i] === b[i]) { i++; }
return a.substr(0, i);
}),
otherPart = keys.map(function (e) { return e.slice(samePart.length); }).sort(function (a, b) { return a - b; }),
transposedMatrix = [].map.call(otherPart, function (col, i) { return dict[samePart + col].map(function (_, j) { return dict[samePart + col][j]; }); });

Related

How would I refactor my code using filter javascript

I want to join two arrays without having any repeating elements:
function union(arr1, arr2) {
var obj = {};
for (var i = arr1.length-1; i >= 0; -- i)
obj[arr1[i]] = arr1[i];
for (var i = arr2.length-1; i >= 0; -- i)
obj[arr2[i]] = arr2[i];
var res = []
for (var k in obj) {
if (obj.hasOwnProperty(k))
res.push(obj[k]);
}
return res;
}
union([1, 3, 5], [3, 6, 9]); //[1, 3, 5, 6, 9]
Using the spread operator, ...arr1, we can combine both arrays into one then by creating a Set we can have an array with only unique values automatically.
function union(arr1, arr2){
const unioned = [...arr1, ...arr2];
return new Set(unioned);
}
union([1, 3, 5], [3, 6, 9]);
https://medium.com/front-end-weekly/es6-set-vs-array-what-and-when-efc055655e1a
I was able to figure it out:
function union(arr1, arr2) {
return arr1.concat(arr2.filter((item) => arr1.indexOf(item) < 0))
}
union([1, 3, 5], [3, 6, 9]); //[1, 3, 5, 6, 9]

How to find the sum of the elements of an arbitrary JavaScript array

There is such an arbitrary array in which I need to find the sum of all numbers without using Array.isArray:
let arr = [[1, 2, 3, [4, 5, [6, 7]]], [8, [9, 10]]];
The solution should look something like this:
let arr = [[1, 2, 3, 4, 5], [6, 7, 8], [9, 10]];
for (let i = 0; i < arr.length; i++) {
for (let j = 0; j < arr[i].length; j++) {
console.log(arr[i][j]);
}
}
Could you please advise me on how to achieve this?
Solution
Use flat and reduce methods to accomplish this.
Example
let arr = [[1, 2,
3, [4, 5, [6, 7]]],
[8, [9, 10]]];
arr.flat(Infinity).reduce((a, b) => a + b, 0)
References
Flat: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/flat
Reduce: https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Array/reduce
You could take Array#flat and Array#reduce the array or check the instance of the given value with instanceof operator.
function getSum1(array) {
return array.flat(Infinity).reduce((sum, value) => sum + value, 0);
}
function getSum2(array) {
let sum = 0;
for (const value of array) {
sum += value instanceof Array
? getSum2(value)
: value
}
return sum;
}
let array = [[1, 2, 3, [4, 5, [6, 7]]], [8, [9, 10]]];
console.log(getSum1(array));
console.log(getSum2(array));
you use lodash for this:
var _ = require("lodash");
var arr = [[1, 2, 3, [4, 5, [6, 7]]], [8, [9, 10]]];
flatArr = _.flattenDeep(arr);
flatArr.reduce((sum, value) => sum + value, 0);

How can I filter an array without using filter()?

The objective is to iterate through the outer loop and then through the inner loop. After that we need to filter the parameter which is passed as 'elem'. The new Array (newArr) should return an array without the 'elem' element.
function filteredArray(arr, elem) {
let newArr = [];
for(var i = 0; i<= arr.length; i ++){
for(var j = 0; j<=arr[i].length ; j++){
if(arr.indexOf(elem)!= -1){
newArr.push(arr[i]);
}
}
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3));
What is wrong with this logic ?
If you want multidimensional array as a result
function filteredArray(arr, elem) {
let newArr = [];
for (var i = 0; i < arr.length; i++) {
let subArray=[];
for (var j = 0; j < arr[i].length; j++) {
if (arr[i][j] !==elem) {
subArray.push(arr[i][j]);
}
}
newArr.push(subArray)
}
return newArr;
}
console.log((filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)));
And if you want flat array as a result
function filteredArray(arr, elem) {
let newArr = [];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
if (arr[i][j] !==elem) {
newArr.push(arr[i][j]);
}
}
}
return newArr;
}
console.log((filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)));
Without using filter method, But if you can use map and reduce will be simplified and can avoid handling with indexes.
const filteredArray = (arr, elem) =>
arr.map((data) =>
data.reduce((acc, cur) => (cur !== elem && acc.push(cur), acc), [])
);
console.log(
filteredArray(
[
[3, 2, 3],
[1, 6, 3],
[3, 13, 26],
[19, 3, 9],
],
3
)
);
If you need flat array, just change map to flatMap in above code.
const filteredFlatArray = (arr, elem) =>
arr.flatMap((data) =>
data.reduce((acc, cur) => (cur !== elem && acc.push(cur), acc), [])
);
console.log(
filteredFlatArray(
[
[3, 2, 3],
[1, 6, 3],
[3, 13, 26],
[19, 3, 9],
],
3
)
);
Corrections
i <= arr.length => i < arr.length
arr.indexOf(elem) => arr[i].indexOf(elem)
function filteredArray(arr, elem) {
let newArr = [];
for (var i = 0; i < arr.length; i++) {
for (var j = 0; j < arr[i].length; j++) {
if (arr[i].indexOf(elem) != -1) {
newArr.push(arr[i]);
}
}
}
return newArr;
}
console.log(JSON.stringify(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 3, 9]], 3)));
What is wrong with this logic ?
1-You need to declare empty sub-arrays before accessing them.
newArr[i] = [];
2-You want to push the full array(I assume to save time), if elem is NOT found, correct condition or put in else.
newArr.push(arr[i]); but you should use this
newArr[i] = arr[i]; because i created new empty sub arrays.
3-You need to actually use j to go throught subarray.
newArr[i].push(arr[i][j]);
4-It was already answered, but you need to check you dont overshoot out of array.
i < arr.length
j < arr[i].length
5-You are missing extreme cases.
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 5, 9], [3, 3, 3]], 3));
function filteredArray(arr, elem) {
const newArr = [];
let skip = 0;
for (var i = 0; i < arr.length; i++) {
newArr[i] = [];
skip = arr[i].indexOf(elem);
for (var j = 0; j < arr[i].length; j++) {
if (skip !== -1) {
if (arr[i][j] !== elem) {
newArr[i].push(arr[i][j]);
}
} else {
newArr[i] = arr[i];
break;
}
}
}
return newArr;
}
console.log(filteredArray([[3, 2, 3], [1, 6, 3], [3, 13, 26], [19, 5, 9], [3, 3, 3]], 3));

"Maximum call stack size exceeded" Correct method but not efficient enough? Codewars Kata “Stop the Zombie Apocalypse!”

I am attempting to solve this kata- https://www.codewars.com/kata/stop-the-zombie-apocalypse/train/javascript
I think I have a method that should work, but is too slow/inefficient and I am getting the error "Maximum call stack size exceeded". I would greatly appreciate all responses as dumbed down as possible as I am new to this. If you could point me in the direction of a different way of doing this, or somehow tweaking my method preferably.
function findZombies(matrix) {
var n = matrix.length;
var value = 0;
//create 2 new arrays with 2 extras row and columns
var arr1 = [...Array(n + 2)].map(e => Array(n + 2).fill(value));
var arr2 = [...Array(n + 2)].map(e => Array(n + 2).fill(value));
//change arr1 so that all infected numbers = 2, everything else = 0
//leaving first and last rows and columns blank
for (var i = 0; i < n; i++) {
for (var j = 0; j < n; j++) {
if (matrix[i][j] == matrix[0][0]) {
arr1[i + 1][j + 1] = 2;
}
}
}
//if element in arr1 has a link back to arr[1][1] call the function recursively until there is no link
//Then return arr2 with changed elements.
function recur(arr1, arr2, i, j) {
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i + 1][j]) {
arr2[i][j] = 1;
recur(arr1, arr2, (i + 1), j)
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i][j + 1]) {
arr2[i][j] = 1;
recur(arr1, arr2, i, (j + 1))
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i - 1][j]) {
arr2[i][j] = 1;
recur(arr1, arr2, (i - 1), j)
}
if (arr1[i][j] == 2 && arr1[i][j] == arr1[i][j - 1]) {
arr2[i][j] = 1;
recur(arr1, arr2, i, (j - 1))
} else {
return arr2;
console.log(arr2)
}
}
recur(arr1, arr2, 1, 1);
//clean up array by removing empty outside rows and columns
arr2.shift();
arr2.pop();
for (var i = 0; i < n; i++) {
arr2[i].shift();
arr2[i].pop()
}
console.log(arr2);
}
var matrix = [
[9, 1, 2],
[9, 9, 9],
[7, 4, 9],
[7, 9, 7]
];
var matrix2 = [
[8, 2, 3, 8, 8],
[8, 0, 8, 8, 8],
[1, 2, 8, 4, 8],
[8, 2, 3, 8, 8],
[8, 8, 8, 0, 5]
];
findZombies(matrix)
You could store all valid points (zombies) in a nested hash table with the all zombies and their adjacent zombies.
At the end start with the known zombie at [0][0] and take the array of the ahsh table to visit all connected field. For preventing visiting already visited items, replace the array with undefined.
function findZombies(matrix) {
function go([i, j]) {
if (!tree[i] || !tree[i][j]) return;
result[i][j] = 1;
var temp = tree[i][j];
tree[i][j] = undefined;
temp.forEach(go);
}
var i, j,
result = [],
zombie = matrix[0][0],
tree = {};
for (i = 0; i < matrix.length; i++) {
result.push([]);
for (j = 0; j < matrix[i].length; j++) {
result[i].push(0);
if (matrix[i][j] !== zombie) continue;
if (!tree[i]) tree[i] = {};
tree[i][j] = [[i, j - 1], [i, j + 1], [i - 1, j], [i + 1, j]].filter(([x, y]) => matrix[x] && matrix[x][y] === zombie);
}
}
go([0, 0]);
return result;
}
var matrix = [[9, 1, 2, 3, 4, 1, 2, 9], [9, 9, 9, 2, 1, 5, 9, 9], [9, 2, 9, 3, 7, 9, 1, 9], [6, 9, 9, 9, 0, 9, 2, 9], [5, 4, 3, 9, 9, 9, 4, 9], [9, 3, 9, 5, 8, 9, 9, 9], [9, 9, 9, 9, 9, 9, 7, 9], [9, 9, 1, 2, 3, 9, 8, 9]],
result = findZombies(matrix);
result.forEach(a => console.log(...a));
.as-console-wrapper { max-height: 100% !important; top: 0; }

Chunking array within array algorithm

first question on stackoverflow, i'm struggling with this algorithm. This is supposed to slice my array in 5 like "[[0, 1], [2, 3], [4, 5], [6, 7], [8]]" but all i got is "[ [ 0, 1 ], [ 2, 3 ], [ 4, 5 ], [ 6, 7, 8 ] ]"
function chunkArrayInGroups(arr, size) {
var newArr = [];
console.log(Math.floor(arr.length / size));
for (i = 0; i <= (Math.floor(arr.length / size)) + 1; ++i) {
var cut = size;
newArr.push(arr.splice(0, cut));
}
if (arr.length > 0) {
newArr.push(arr.splice(0, size + (arr.length - size)));
}
return newArr;
}
chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);
// expected - [[0, 1], [2, 3], [4, 5], [6, 7], [8]]
If you have any tips about the way of asking questions, i'd be happy to receive any advice !
Use a simple for loop with Array#slice, because slice doesn't change the length of the original array:
function chunkArrayInGroups(arr, size) {
var chunked = [];
for(var i = 0; i < arr.length; i += size) { // increment i by the size
chunked.push(arr.slice(i, i + size));
}
return chunked;
}
var result = chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);
console.log(result);
Since you are removing element using Array#splice the array length get decreased so instead of calculating the range cache the range for the for loop condition. Although use Math.ceil and avoid the unnecessary if statement.
function chunkArrayInGroups(arr, size) {
var newArr = [],
range = Math.ceil(arr.length / size);
for (i = 0; i < range; i++) {
newArr.push(arr.splice(0, size));
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));
Check this out.
function chunkArrayInGroups(arr, size) {
newArr = [];
for (i=0,j=arr.length; i<j; i+=size) {
newArr.push(arr.slice(i,i+size));
}
return newArr;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));
// expected - [[0, 1], [2, 3], [4, 5], [6, 7], [8]]
Another way to do it is Array#reduce:
function chunkArrayInGroups(arr, size) {
return arr.reduce(function (accum, elem) {
var curr = accum[accum.length - 1];
if (curr.length < size) curr.push(elem); else accum.push([elem]);
return accum;
}, [[]]);
}
var result = chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2);
console.log( JSON.stringify(result) );
Welcome to SO. Here is how I would do that. Let me know if you have any questions about this approach.
function chunkArrayInGroups(arr, size) {
var newArr = [];
while(arr.length > 0){
newArr.push(arr.splice(0, size));
}
return newArr;
}
Functionally you can do as follows;
function chunkArrayInGroups(a,g){
return Array(Math.ceil(a.length/g)).fill()
.map((_,i) => [a[g*i]].concat(a.slice(g*i+1, g*i+g)));
}
var arr = [0, 1, 2, 3, 4, 5, 6, 7, 8];
result = [];
result = chunkArrayInGroups(arr,2);
console.log(JSON.stringify(result));
result = chunkArrayInGroups(arr,3);
console.log(JSON.stringify(result));
result = chunkArrayInGroups(arr,4);
console.log(JSON.stringify(result));
You could use a while loop and splice the length of the wanted size for a grouped array.
function chunkArrayInGroups(array, size) {
var result = [];
while (array.length) {
result.push(array.splice(0, size));
}
return result;
}
console.log(chunkArrayInGroups([0, 1, 2, 3, 4, 5, 6, 7, 8], 2));

Categories