Sort specific element without reordering others [closed] - javascript

Closed. This question is not reproducible or was caused by typos. It is not currently accepting answers.
This question was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Closed 1 year ago.
Improve this question
So I'm trying to write a one-liner to sort an array where I just push all zeroes to the end of the array. This is my code:
const arr = [ 9, 0, 0, 9, 1, 2, 0, 1, 0, 1, 0, 3, 0, 1, 9, 0, 0, 0, 0, 9 ];
arr.sort((a,b) => (a === 0 && b !== 0) ? 1 : (b === 0 && a !== 0) ? -1 : 0);
console.log(`[${arr.join(', ')}]`);
// [9, 9, 1, 2, 1, 1, 3, 1, 9, 9, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]
However, this code also seems to order other elements somehow, for the array
I expect
[9,9,1,2,1,1,3,1,9,9,0,0,0,0,0,0,0,0,0,0]
But I got
[9,9,9,9,1,2,1,1,3,1,0,0,0,0,0,0,0,0,0,0]
Any clues?

I am getting your expected result.
But you can also use filter since it returns a new array. Concat the first one (without zeroes) to the second one (only zeroes).
let arr = [ 9, 0, 0, 9, 1, 2, 0, 1, 0, 1, 0, 3, 0, 1, 9, 0, 0, 0, 0, 9 ];
arr = arr.filter(a => a !== 0).concat(arr.filter(a => a === 0));
console.log(arr);

Pretty much a one liner... sort of. Uses a temp array to store the zeros
let n = [9, 0, 0, 9, 1, 2, 0, 1, 0, 1, 0, 3, 0, 1, 9, 0, 0, 0, 0, 9]
let c = [], newn = n.filter(e => (e === 0 && c.push(e)) ? false : true).concat(c)
console.log(newn)

Related

Javascript for loop odd behavior

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
}

Compare 2 or more consecutive numbers in an array [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 12 months ago.
Improve this question
I have an array: A = [ 2, 2, 0, 0, -1, 1, -1, -1, -1 ]
I want to be able to return true in instances where 2 or more consecutive numbers are the same. So in this array, the output array should have 5 trues with [2,2], [0,0], [-1,-1,-1], [-1,-1] and [-1,-1].
So far I have used slice and map on the array through 2 consecutive numbers and have gotten 4 trues.
const solution = (A) => {
let compare = A.slice(1).map((n,i) => {
return (n === A[i])
})
console.log(compare) // => [ true, false, true, false, false, false, true, true ]
}
const A = [ 2, 2, 0, 0, -1, 1, -1, -1, -1 ];
solution(A);
But getting that fifth true on the [-1,-1,-1] is eluding me.
Currently the compare output I have is only going through 2 consecutive numbers which is why it's given me 4 trues. My question is basically how to go about checking for the 3 or more consecutive numbers.
My final would be something like
compare.filter(word => word === true).length
to get 5.
Perhaps what would actually be useful is the groups:
const findGroups = (arr) => arr.reduce((result, value, index) => {
let windowLength = 2;
while (arr[index + windowLength - 1] === value) {
result.push(arr.slice(index, index + windowLength));
windowLength++;
}
return result;
}, []);
console.log(findGroups([2, 2, 0, 0, -1, 1, -1, -1, -1])); // [[2, 2], [0, 0], [-1, -1], [-1, -1, -1], [-1, -1]]
console.log(findGroups([4, 4, 4, 4])); // [[4, 4], [4, 4, 4], [4, 4, 4, 4], [4, 4], [4, 4, 4], [4, 4]]
That gives you an array of the groups of consecutive values. If you just want 5, it's the .length, or you can calculate it directly rather than building unnecessary arrays:
const findGroupCount = (arr) => arr.reduce((result, value, index) => {
let windowLength = 2;
while (arr[index + windowLength - 1] === value) {
result++;
windowLength++
}
return result;
}, 0);
console.log(findGroupCount([2, 2, 0, 0, -1, 1, -1, -1, -1])); // 5
console.log(findGroupCount([4, 4, 4, 4])); // 6

Map current array with values by index from another array [closed]

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 last year.
Improve this question
Let's imagine I have to arrays:
const array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const array2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
array2.map((elem, index) => {
// Looking here to return the value from array1 by index
});
From array2 I am looking to return values from array1, by the index position, but just in the range 1 -10. The idea is that it should go in a kind of circle where the start value is 1 and end value is 10.
The expected output for the above example is:
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 1, 2, 3, 4, 5]
More examples of how it should work:
Index 1 from array2 -> return 1 from array1
Index 10 from array2 -> return 10 from array1
Index 12 from array2 -> return 2 from array1
Index 20 from array2 -> return 10 from array1
Index 999 from array2 -> return 9 from array1
Index 1225 from array2 -> return 5 from array1
You can use the remainder operator (%):
const array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const array2 = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0];
const result = array2.map((elem, index) => array1[index % array1.length]);
console.log(result);
You really don't need to have array2, which provides no information other than its length -- the zeroes are not relevant. So given just the length, it could be as follows:
const array1 = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
const length = 15;
const result = Array.from({length}, (elem, index) => array1[index % array1.length]);
console.log(result);
You probably don't need two arrays to achieve this. You could use the modulo operator to perform 'wrap around' like lookups.
For example:
array1[index % (array1.length)]
if you absolutely need the info in a second array, something like this would achieve the desired result:
array2.forEach((_, index) => array2[index] = array1[index % (array1.length)]);

How to check every item in a 2D array for specific condition?

:) 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));

How can I collapse a multidimensional array into a single array with a common value? [closed]

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));

Categories

Resources