Related
This question already has answers here:
Zip arrays in JavaScript?
(5 answers)
Closed 2 months ago.
I have two arrays. One contains a series of dates. The other array contains a series of data. What is the best way to combine the two arrays into one array of objects.
As an example the first element of the first array will be in the same object as the first element in the second array.
HERE ARE THE TWO ARRAYS
const datesArray = [
"2017-01-01",
"2017-01-02",
"2017-01-03",
"2017-01-04",
"2017-01-05",
"2017-01-06",
"2017-01-07",
"2017-01-08",
"2017-01-09",
"2017-01-10",
"2017-01-11",
"2017-01-12",
"2017-01-13",
"2017-01-14",
"2017-01-15",
"2017-01-16",
"2017-01-17",
"2017-01-18",
"2017-01-19",
"2017-01-20",
"2017-01-21",
"2017-01-22",
"2017-01-23",
"2017-01-24",
"2017-01-25",
"2017-01-26",
"2017-01-27",
"2017-01-28",
"2017-01-29",
"2017-01-30",
"2017-01-31",
];
const snowfallArray = [
0.98, 0, 0, 0, 0, 0, 0.35, 0.42, 0, 0.14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
HERE IS MY EXPECTED OUTPUT
let combinedArray = [{
date: *first element from dates array*,
snowFall: *first element from snowfall array*
},
{
date: *second element from dates array*,
snowFall: *second element from snowfall array*
}]
EXPECTED OUTPUT EX:
let combinedArray = [{date: '2017-01-01', snowFall: 0.98},{date: '2017-01-02', snowFall: 0}]
I do not even know where to begin..
Assuming the arrays are of equal lengths, then this should work:
const datesArray = [
"2017-01-01",
"2017-01-02",
"2017-01-03",
"2017-01-04",
"2017-01-05",
"2017-01-06",
"2017-01-07",
"2017-01-08",
"2017-01-09",
"2017-01-10",
"2017-01-11",
"2017-01-12",
"2017-01-13",
"2017-01-14",
"2017-01-15",
"2017-01-16",
"2017-01-17",
"2017-01-18",
"2017-01-19",
"2017-01-20",
"2017-01-21",
"2017-01-22",
"2017-01-23",
"2017-01-24",
"2017-01-25",
"2017-01-26",
"2017-01-27",
"2017-01-28",
"2017-01-29",
"2017-01-30",
"2017-01-31",
];
const snowfallArray = [
0.98, 0, 0, 0, 0, 0, 0.35, 0.42, 0, 0.14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
const combined = snowfallArray.map((snowfall, index) => ({snowfall, date: datesArray[index]}));
console.log(combined);
assuming your array are the same length:
const datesArray = [
"2017-01-01",
"2017-01-02",
"2017-01-03",
"2017-01-04",
"2017-01-05",
"2017-01-06",
"2017-01-07",
"2017-01-08",
"2017-01-09",
"2017-01-10",
"2017-01-11",
"2017-01-12",
"2017-01-13",
"2017-01-14",
"2017-01-15",
"2017-01-16",
"2017-01-17",
"2017-01-18",
"2017-01-19",
"2017-01-20",
"2017-01-21",
"2017-01-22",
"2017-01-23",
"2017-01-24",
"2017-01-25",
"2017-01-26",
"2017-01-27",
"2017-01-28",
"2017-01-29",
"2017-01-30",
"2017-01-31",
];
const snowfallArray = [
0.98, 0, 0, 0, 0, 0, 0.35, 0.42, 0, 0.14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
];
const results = [];
for (let i=0; i< snowfallArray.length; i++){
results.push({
date: datesArray[i],
snowFall: snowfallArray[i]
})
}
console.log(results);
I'm writing an algorithm to solve a sudoku puzzle and I'm getting some weird behavior. My first draft below did not give me an error, but it was modifying the array. Then I realized (because I am new to JavaScript) that I have to put let before the var in the for loop, so I changed it.
The weird behavior is that when I change it to let row and let col in the for loop it no longer modifies the puzzle param array. I do not understand how adding the let word to the for loop changes this?
test = [
[8, 0, 6, 0, 1, 0, 0, 0, 0],
[0, 0, 3, 0, 6, 4, 0, 9, 0],
[9, 0, 0, 0, 0, 0, 8, 1, 6],
[0, 8, 0, 3, 9, 6, 0, 0, 0],
[7, 0, 2, 0, 4, 0, 3, 0, 9],
[0, 0, 0, 5, 7, 2, 0, 8, 0],
[5, 2, 1, 0, 0, 0, 0, 0, 4],
[0, 3, 0, 7, 5, 0, 2, 0, 0],
[0, 0, 0, 0, 2, 0, 1, 0, 5]
]
let result = solve(test)
console.log(result)
printPuzzle(test)
function solve(puzzle) {
for (row = 0; row < 9; row++) {
for (col = 0; col < 9; col++) {
if (puzzle[row][col] === 0) {
for (number = 1; number < 9; number++) {
if (isValidPlacement(puzzle, number, row, col)) {
puzzle[row][col] = number
if (solve(puzzle)) {
return true
} else {
puzzle[row][col] = 0
}
}
}
return false
}
}
}
return true
}
:) I'm creating a maze using JS and P5, with a two dimensional array filled with numbers 0-8. 0 are empty spots, 1 are walls, 2 is the character you walk with, 3 is the exit and 4-8 are items that randomly spawn. In order to exit the maze (through 3, which is set on a fixed spot), all items need to be collected (if you walk over an item, the value of this spot changes back to 0), so every value in the array should be below 4 in order to exit. Now I need a way to check if this is the case.
I tried it with every() but I guess this only works for regular arrays. I suppose I need a for loop but I don't know this should look. So that's where I need help!
My maze consists of 18 rows and columns, like so (but then 15 more rows)
let maze = [
[1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1],
[1,2,0,0,0,0,1,0,1,0,0,0,0,1,0,0,1,0,1,0,0,0,3],
[1,1,1,1,1,0,1,0,0,0,1,1,0,0,0,0,1,0,1,0,1,0,1]
]
The items spawn randomly, this already works. Now I tried checking if every value is <= 3, with the every, like so
function checkBoard(mazenumbers){
return mazenumbers <= 3;
}
function alertMazenumbers() {
alert(maze.every(checkBoard));
}
And want this to display through an alert, once you walk into the exit location, like this
else if(direction === 'right') {
if(maze[playerPos.y][playerPos.x + 1] == 3) {
alertMazenumbers();
}
I want to get an alert with true if every value is <= 3, and false if not.
Currently, with this every(), I do get the alert but it only returns false, even when all items are cleared and it should return true.
You are on the right track using every!
The maze is an array of arrays (as Denys mentioned in his comment), so you have to use every twice, like so:
function canExitMaze(maze) {
return maze.every(row => row.every(cell => cell <= 3))
}
If you don't recognize the arrow function syntax (=>) this article explains it.
Hope this helps!
You can check if every point in the maze is <=3 by doing this
const isTrue = num => num <= 3; // is a single cell true
const isRowTrue = row => row.every(isTrue); // are all cells in a row true
const isMazeTrue = rows => rows.every(isTrue); // are all cells in all rows true
const maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1]
];
console.log(isMazeTrue(maze));
Method 1: Check if every array only contains numbers that are <= 3
let maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1]
];
function testMaze(maze) {
return maze.every(row => row.every(itemIsValid));
}
function itemIsValid(item) {
return item <= 3;
}
console.log(testMaze(maze));
maze[2][4] = 4;
console.log(testMaze(maze));
Method 2: Merge the arrays and search the numbers
var maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1]
];
function testMaze(maze) {
return [].concat(...maze).every(itemIsValid);
}
function itemIsValid(item) {
return item <= 3;
}
console.log(testMaze(maze));
maze[2][4] = 4;
console.log(testMaze(maze));
Method 3: Convert the maze to a string and use regex
var maze = [
[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],
[1, 2, 0, 0, 0, 0, 1, 0, 1, 0, 0, 0, 0, 1, 0, 0, 1, 0, 1, 0, 0, 0, 3],
[1, 1, 1, 1, 1, 0, 1, 0, 0, 0, 1, 1, 0, 0, 0, 0, 1, 0, 1, 0, 1, 0, 1]
];
function testMaze(maze) {
//or maze.toString().match(/\d+/g).every(x => itemIsValid(+x));
return !/[4-8]/g.test(`${maze}`);
}
function itemIsValid(item) {
return item <= 3;
}
console.log(testMaze(maze));
maze[2][4] = 4;
console.log(testMaze(maze));
Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 4 years ago.
Improve this question
Edited to be more clear about my question:
I have a a multidimensional array that looks like this
var data = [
[2017, 1, 0, 0, 0, 0],
[2017, 0, 0, 23, 0, 0],
[2017, 0, 0, 0, 0, 9],
[2017, 0, 12, 0, 0, 0],
[2017, 0, 0, 0, 18, 0]
];
I'm trying to flatten this data into something that looks like this:
var data = [2017, 1, 12, 23, 18, 9];
Where in:
The year in Column #0 will be the same throughout rows.
For each row, Columns #1 through #5 will only have one non-zero element.
Is there an easy way to do this without having to process the data through multiple for loops? I was hoping maybe there was some native method in the Array type or function in a library out there.
Loop over the array and check take the number if it is higher than the current number:
var data = [
[2017, 1, 0, 0, 0, 0],
[2017, 0, 0, 23, 0, 0],
[2017, 0, 0, 0, 0, 9],
[2017, 0, 12, 0, 0, 0],
[2017, 0, 0, 0, 18, 0]
];
let newdata = [];
for (row of data) {
for (let i = 0; i<row.length; ++i) {
newdata[i] = (!newdata[i] || row[i] > newdata[i]) ? row[i] : newdata[i];
}
}
console.log(newdata);
outputs:
[2017, 1, 12, 23, 18, 9]
Use Array.map() in the 1st line to get a column index, and reduce all rows to a single non 0 value on that column:
const data = [
[2017, 1, 0, 0, 0, 0],
[2017, 0, 0, 23, 0, 0],
[2017, 0, 0, 0, 0, 9],
[2017, 0, 12, 0, 0, 0],
[2017, 0, 0, 0, 18, 0]
];
const result = data[0]
.map((_, i) =>
data.reduce((r, e) => r ? r : e[i], 0)
);
console.log(result);
Actually, based on the next two conditions:
The year in Column #0 will be the same throughout rows.
For each row, Columns #1 through #5 will only have one non-zero element.
You can use reduce() and findIndex() on the inners arrays to find the first number greater than zero whose index is not zero, and then put this on the related index of the accumulated result. This will improve perfomance a litle because you don't need to iterate the whole inner array on all the iterations of the reduce method.
var data = [
[2017, 1, 0, 0, 0, 0],
[2017, 0, 0, 23, 0, 0],
[2017, 0, 0, 0, 0, 9],
[2017, 0, 12, 0, 0, 0],
[2017, 0, 0, 0, 18, 0]
];
let res = data.slice(1).reduce((acc, curr) =>
{
let found = curr.findIndex((n, idx) => n > 0 && idx > 0);
acc[found] = curr[found];
return acc;
}, data[0]);
console.log(JSON.stringify(res));
I have the following array:
arr = [
[ 1, 1, 1, 1, 1, 1, 1 ],
[ 1, 1, 0, 0, 1, 1, 0 ],
[ 1, 0, 0, 0, 1, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 1, 0, 1, 0, 0, 2 ],
[ 1, 0, 0, 1, 0, 2, 4 ],
[ 0, 0, 0, 0, 2, 4, 4 ],
[ 0, 0, 0, 0, 4, 4, 0 ],
[ 1, 1, 1, 0, 0, 0, 0 ],
[ 1, 1, 0, 2, 0, 0, 2 ],
[ 1, 0, 0, 4, 0, 2, 0 ],
[ 0, 0, 0, 4, 2, 0, 0 ],
[ 0, 0, 2, 0, 0, 0, 1 ],
[ 0, 2, 4, 0, 0, 1, 2 ],
[ 2, 4, 4, 2, 1, 2, 4 ],
[ 4, 4, 0, 0, 2, 4, 0 ]
]
Currently, I'm getting the max array sum in arr i.e 19 like this
function getMaxSum(arr) {
return arr.map(e => e.reduce((a, b) => a + b, 0)).sort((a,b) => a - b)[arr.length - 1];
}
I need to know is there any better way to achieve this?
I'm using array length of the original array to get the last element of resulting array because in this case, length of original array and resulting array is same. If the scenario is different then how can I use the length of the resulting array here:
return arr.map(e => e.reduce((a, b) => a + b, 0)).sort((a,b) => a - b)[HERE - 1];
Not a huge improvement, but it seems a little more literal to spread the values into Math.max
const data = [
[ 1, 1, 1, 1, 1, 1, 1 ],
[ 1, 1, 0, 0, 1, 1, 0 ],
[ 1, 0, 0, 0, 1, 0, 0 ],
[ 0, 0, 0, 0, 0, 0, 0 ],
[ 0, 1, 0, 1, 0, 0, 2 ],
[ 1, 0, 0, 1, 0, 2, 4 ],
[ 0, 0, 0, 0, 2, 4, 4 ],
[ 0, 0, 0, 0, 4, 4, 0 ],
[ 1, 1, 1, 0, 0, 0, 0 ],
[ 1, 1, 0, 2, 0, 0, 2 ],
[ 1, 0, 0, 4, 0, 2, 0 ],
[ 0, 0, 0, 4, 2, 0, 0 ],
[ 0, 0, 2, 0, 0, 0, 1 ],
[ 0, 2, 4, 0, 0, 1, 2 ],
[ 2, 4, 4, 2, 1, 2, 4 ],
[ 4, 4, 0, 0, 2, 4, 0 ]
]
function getMaxSum(arr) {
return Math.max(...arr.map(e => e.reduce((a, b) => a + b, 0)))
}
console.log(getMaxSum(data))
As #Rajesh points out, Math.max is faster that a sort:
const numbers = Array(10000).fill().map((x,i)=>i);
const max = numbersIn => Math.max(...numbersIn);
const getMaxViaSort = numbersIn => numbersIn
.sort((a, b) => a > b ? -1 : 1)[0]
console.time('max');
max(numbers);
console.timeEnd('max');
console.time('max via sort');
getMaxViaSort(numbers);
console.timeEnd('max via sort');
The optimal strategy should be one where we need the least interaction with the arrays.
In my method i test the array products individually and compare that with a variable inside my loop. In this way i don't need to run a new implied loop to have Math.max check all my entries again, netting a speed boost.
This also saves on memory management as i don't need to map and return a new array of results for Math.max.
At the end of the loop i simply return the variable.
var data = [
[1, 1, 1, 1, 1, 1, 1],
[1, 1, 0, 0, 1, 1, 0],
[1, 0, 0, 0, 1, 0, 0],
[0, 0, 0, 0, 0, 0, 0],
[0, 1, 0, 1, 0, 0, 2],
[1, 0, 0, 1, 0, 2, 4],
[0, 0, 0, 0, 2, 4, 4],
[0, 0, 0, 0, 4, 4, 0],
[1, 1, 1, 0, 0, 0, 0],
[1, 1, 0, 2, 0, 0, 2],
[1, 0, 0, 4, 0, 2, 0],
[0, 0, 0, 4, 2, 0, 0],
[0, 0, 2, 0, 0, 0, 1],
[0, 2, 4, 0, 0, 1, 2],
[2, 4, 4, 2, 1, 2, 4],
[4, 4, 0, 0, 2, 4, 0]
];
function getMaxSum1(arr) {
//The original method
return arr.map(function (e) { return e.reduce(function (a, b) { return a + b; }, 0); }).sort(function (a, b) { return a - b; })[arr.length - 1];
}
function getMaxSum2(arr) {
//From https://stackoverflow.com/a/51704254/5242739
return Math.max.apply(Math, arr.map(function (e) { return e.reduce(function (a, b) { return a + b; }, 0); }));
}
function sumArray(arr) {
var val = 0;
for (var index = 0; index < arr.length; index++) {
val += val;
}
return val;
}
function getMaxSum3(arr) {
//My method
var max;
for (var i = 0; i < arr.length; i++) {
var val = sumArray(arr[i]);
if (max === void 0 || val > max) {
max = val;
}
}
return max;
}
//TEST
//parameters
var runs = 10;
var tests = 100000;
//output area
var out = document.body.appendChild(document.createElement("pre"));
//test functions
function simulate1() {
var t = tests;
var dt = Date.now();
while (t--) {
getMaxSum1(data);
}
out.textContent += 'getMaxSum1 took: ' + (Date.now() - dt) + "ms\n";
requestAnimationFrame(simulate2);
}
function simulate2() {
var t = tests;
var dt = Date.now();
while (t--) {
getMaxSum2(data);
}
out.textContent += 'getMaxSum2 took: ' + (Date.now() - dt) + "ms\n";
requestAnimationFrame(simulate3);
}
function simulate3() {
var t = tests;
var dt = Date.now();
while (t--) {
getMaxSum3(data);
}
out.textContent += 'getMaxSum3 took: ' + (Date.now() - dt) + "ms\n\n";
if (runs--) {
requestAnimationFrame(simulate1);
}
}
//start
simulate1();
pre {
max-height: 200px;
overflow-y: scroll;
background-color: #eee;
}
I included OliverRadini's answer to compare the relative speed boosts.