Loop through 2d-array diagonally - javascript

I've been searching on this website for an valid answer for my question so far i haven't find one so i'm posting a question
I have to loop trough an 2d-array diagonally to check if the value === 0. Whenever i try this it only goes trough the array of the 2d-array and then it stops
Basically i need to get the indices 0,0 1,1 2,2...
function isValidDistanceMatrix(nss) {
let row_count = nss.length;
let row_sizes = nss.map(ns => ns.length);
let maxRow = Math.max(...row_sizes);
let min = Math.min(...row_sizes);
if (maxRow === row_count && min === maxRow){
for (let x = 0; x < row_count; x++){
if (nss[x][x] === 0){
return true;
}
}
}
return false;
}
[[0, 5, 6, 1], [5, 0, 1, 1], [6, 1, 0, 1], [1, 1, 1, 0]] returns true
[[0, 5, 6, 1], [5, 4, 1, 1], [6, 1, 5, 7], [1, 1, 1, 0]] returns false

You are returning true after checking the first value instead of checking all of the values.
Change it to return false for any non-zero value, and return true at the end :
function isValidDistanceMatrix(nss) {
let row_count = nss.length;
let row_sizes = nss.map(ns => ns.length);
let maxRow = Math.max(...row_sizes);
let min = Math.min(...row_sizes);
if (maxRow !== row_count || min !== row_count) return false; // change to return false
for (let x = 0; x < row_count; x++) {
if (nss[x][x] !== 0) { // change to not equal
return false; // change to false on the first non-zero
}
}
return true; // change to return true after all values are checked
}
Alternatively, it can be simplified with the Array.prototype.every() method (not tested) :
const isValidDistanceMatrix = nss =>
nss.every((row, index) => row.length === nss.length && row[index] === 0);

Related

I need my functions the stop running and break once a condition is meet, without an error popping up

I am trying to make a sudoku solver. the code works, However when there are no more 0(zeros) in the table that means my sudoku table is solved. if the sudoku table has been solve I want everything to stop running. The problem is I have not found a good way to stop program from running when it is solved. I am open to suggestions.
the case that is supposed to stop the program from running is function find_empty_space(table), it is the first if condition, however in the function sudoku_solver(table) it calls var values = find_empty_space(table); and since I don't return anything if this case occurs an error happens.
I tried adding a if condition below var values = find_empty_space(table); where values == null then nothing happens so the function can stop but that for some reason ruins the sudoku solver from working. if anyone has another idea how to stop my program and all other functions after condition is meet please lmk
var sudoku_1 = [
[0, 0, 0, 0],
[1, 0, 2, 0],
[0, 1, 4, 0],
[2, 0, 0, 1],
];
var table = sudoku_1;
function find_empty_space(table) {
if (
table[0].indexOf(0) == -1 &&
table[1].indexOf(0) == -1 &&
table[2].indexOf(0) == -1 &&
table[3].indexOf(0) == -1
) {
console.log("Sudoku Solver has solved your table");
var solved_table = table;
} else {
for (var r = 0; r < 5; r++) {
for (var c = 0; c < 5; c++) {
console.log(`row: ${r}`); //!for testing
console.log(`column: ${c}`); //!for testing
// if object in array is equal to 0 then it means the space is empty
if (table[r][c] == 0) {
return [r, c];
}
}
}
}
}
function check_if_number_can_go_in_position(table, n, r, c) {
console.log("function check_if_number_can_go_in_position()");
console.log(`row ${table[r]}`);
// var below makes a array of tables column that is need to search for n
var column_c = table.map((d) => d[c]);
console.log(`col ${column_c}`);
if (table[r].indexOf(n) != -1) {
console.log("backtrack r");
return false;
}
if (column_c.indexOf(n) != -1) {
console.log("backtrack c");
return false;
}
return true;
}
// this is the main function
function sudoku_solver(table) {
var values = find_empty_space(table);
console.log(values);
var r = values[0];
var c = values[1];
console.log("in one");
for (var n = 1; n < 5; n++) {
console.log(`n = ${n}`);
if (check_if_number_can_go_in_position(table, n, r, c) == true) {
table[r][c] = n;
console.table(table);
sudoku_solver(table);
}
}
table[r][c] = 0;
}
sudoku_solver(table);
Assuming that this is for the 16x16 Sudoku variant since the input in the OP is only 4x4 -- going along with this assumption then you need to find all of the blanks (represented as a 0) in a box. In the following example, function blankMap(box) takes a 2D array of any size and returns an array of pairs. An array of pairs is a 2D array of N rows and 2 colunms. In each pair (or sub-array) is the location of a 0 -- the first colunm (Array[N][0]) represents the index number of a row, the second colunm (Array[N][1]) represents the index number of a column.
INPUT
OUTPUT
const box9 = [
const box9X = [
[0, 12, 0, 9],
[0, 0], [0, 2],
[16, 3, 0, 8],
[1, 2],
[0, 0, 0, 0],
[2, 0], [2, 1], [2, 2], [2, 3],
[10, 5, 2, 0]
[3, 3]
];
];
/* INPUT
A 4 row by 4 colunm table represents 1 of a total of 16 sub-tables.
*/
const box0 = [
[0, 5, 13, 0],
[10, 0, 0, 0],
[7, 11, 3, 0],
[0, 0, 0, 0]
];
const box13 = [
[1, 2, 3, 4],
[5, 6, 7, 8],
[9, 10, 11, 12],
[13, 14, 15, 16]
];
const blankMap = box =>
box.flatMap((arr, row) => // 1st grab each sub-array (~arr~)
arr.flatMap((num, col) => // On each ~arr~,...
num === 0 ? [[row, col]] : [])); /* ...if it's a ~0~ ~?~ then return the position in double
brackets: ~[[row, col]]~ otherwise ~:~ return an empty array ~[]~.*/
// A utility to verify if a box is completed
const isDone = array => array.length < 1;
console.log('box0=-=-=-=-=-=-=-=-=-=-=-=-=');
let b0 = blankMap(box0);
console.log(JSON.stringify(b0));
console.log('box0 is complete: '+isDone(b0));
console.log('box13-=-=-=-=-=-=-=-=-=-=-=-=');
let b13 = blankMap(box13);
console.log(JSON.stringify(b13));
console.log('box13 is complete: '+isDone(b13));
The .flatMap() method was used twice: once to iterate through the outer array and grab the sub-arrays, and once to iterate through each sub-array to find the 0s. .flatMap() is the .map() and .flat() methods combined so if you want the return as a 2D array, wrap it in brackets (double if another .flatMap() is working on the same array). Inversely, if you want to totally ignore an iteration then return an empty array [].
Marked the added code
function find_empty_space(table) {
// function goes from right to left of table finding every empty space, empty space == 0,
//for loops go through 1-4
// var meanings r = row, c = column
if (
table[0].indexOf(0) == -1 &&
table[1].indexOf(0) == -1 &&
table[2].indexOf(0) == -1 &&
table[3].indexOf(0) == -1
) {
console.log("Sudoku Solver has solved your table");
var solved_table = table;
return true; // ***** added this
} else {
for (var r = 0; r < 5; r++) {
for (var c = 0; c < 5; c++) {
console.log(`row: ${r}`); //!for testing
console.log(`column: ${c}`); //!for testing
// if object in array is equal to 0 then it means the space is empty
if (table[r][c] == 0) {
return [r, c];
}
}
}
}
}
// this is the main function
function sudoku_solver(table) {
// contains all other sub functions this is the main function
//r = row, c = column
// function goes from right to left of table finding every empty space, empty
var values = find_empty_space(table);
if (values === true) return true; // ***** added this
console.log(values);
var r = values[0];
var c = values[1];
console.log("in one");
for (var n = 1; n < 5; n++) {
console.log(`n = ${n}`);
if (check_if_number_can_go_in_position(table, n, r, c) == true) {
table[r][c] = n;
console.table(table);
if (sudoku_solver(table) === true) // ***** changed this
return true; // ***** added this
}
}
table[r][c] = 0;
}
sudoku_solver(table);

Checking whether array contains incremental elements if one is removed

I would like to write a function that checks whether or not an array would be incremental if we were to remove one element from the array. So for example an array like
[1,3,4,2,8]
Would return true because if we remove 2, the array would be incremental ie [1,3,4,8]
To solve this I created a function that iterates through the array, checks whether n is less than n+1 creating an array of true and false values depending on whether the element we are iterating through meets the condition stated.
In cases where n+1 is less than or equal to n; I then have another condition that checks whether n+1 is less than n-1, returning 'very false' in this instance.
I then want to return false if my new Array indicates that removing one element will not leave me with an array of incremental values. I check for by checking whether;
i.) my new array contains more than one false value
ii.) my new array contains the value 'very false' only in instances if very false is not the last element in my array
iii.) my array contains both very false and false
Struggling to get this logic to work. I added a few test cases I am struggling to get right
function solution(sequence) {
let newArr = [];
for(let i = 0; i < sequence.length - 1; i++) {
sequence[i] < sequence[i+1] ? newArr.push(true)
: sequence[i+1] <= sequence[i-1] ? newArr.push('very false')
:newArr.push(false)
}
return (newArr.filter(i => i === false).length) > 1 || ( (newArr.includes('very false')) && (newArr[newArr.length - 1] !== 'very false')) || ( newArr.includes(false) && newArr.includes('very false')) ? false : true;
}
//TEST CASES
let one = [1, 2, 3, 4, 5, 3, 5, 6] //I get this right
let two = [40, 50, 60, 10, 20, 30] //I get this right
let three = [1, 2, 3, 4, 3, 6] //I get this wrong
let four = [1, 4, 10, 4, 2] // I get this wrong
//EXPECTED OUTCOMES
console.log(solution(one)) => false;
console.log(solution(two)) => false;
console.log(solution(three)) => true;
console.log(solution(four)) => false;
FYI: This is not for an assignment or test
The next provided solution uses an every based approach where one would count the amount of violations of the OP's criteria / requirements for a possibly incremental array. Depending on whether a violation has taken place one would compare the current values against the most recent value which caused the violation or one would just simply compare two consecutive array items.
As soon as the maximum allowed violation count gets exceeded, every immediately exits / breaks its iteration with a false boolean return value which also becomes the return value of the below implemented canBeMadeIncremental function; otherwise the return value of both processes is true.
function canBeMadeIncremental(arr) {
let violationCount = 0;
let comparisonValue = null;
return arr.every((value, idx, arr) => {
let isAchievable = true;
if (idx >= 1) {
comparisonValue = comparisonValue ?? arr[idx - 1];
if (comparisonValue >= value) {
++violationCount;
} else {
comparisonValue = null;
}
isAchievable = (violationCount <= 1);
}
return isAchievable;
});
}
console.log(
"canBeMadeIncremental([1, 2, 3, 4, 5, 3, 5, 6]) ?..",
canBeMadeIncremental([1, 2, 3, 4, 5, 3, 5, 6]) // false
);
console.log(
"canBeMadeIncremental([40, 50, 60, 10, 20, 30]) ?..",
canBeMadeIncremental([40, 50, 60, 10, 20, 30]) // false
);
console.log(
"canBeMadeIncremental([1, 2, 3, 4, 3, 6]) ?..",
canBeMadeIncremental([1, 2, 3, 4, 3, 6]) // true
);
console.log(
"canBeMadeIncremental([1, 4, 10, 4, 2]) ?..",
canBeMadeIncremental([1, 4, 10, 4, 2]) // false
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
The above code example could be easily refactored into a more generic function which provides data about whether an incremental array is possible and if yes, how to achieve it (e.g. which index / indices need/s to be removed) ...
function howToMakeIncremental(arr) {
let isAchievable = true;
let comparisonValue = null;
let violationCount = 0;
const violatingIndexList = [];
arr.every((value, idx, arr) => {
if (idx >= 1) {
comparisonValue = comparisonValue ?? arr[idx - 1];
if (comparisonValue >= value) {
violatingIndexList.push(idx);
++violationCount;
} else {
comparisonValue = null;
}
isAchievable = (violationCount <= 1);
}
return isAchievable;
});
const howTo = { isAchievable };
if (isAchievable) {
howTo.violatingIndexList = violatingIndexList;
}
return howTo;
}
console.log(
"howToMakeIncremental([1, 2, 3, 4, 5, 3, 5, 6]) ?..",
howToMakeIncremental([1, 2, 3, 4, 5, 3, 5, 6]) // { isAchievable: false }
);
console.log(
"howToMakeIncremental([40, 50, 60, 10, 20, 30]) ?..",
howToMakeIncremental([40, 50, 60, 10, 20, 30]) // { isAchievable: false }
);
console.log(
"howToMakeIncremental([1, 2, 3, 4, 3, 6]) ?..",
howToMakeIncremental([1, 2, 3, 4, 3, 6]) // { isAchievable: true, violatingIndexList: [4] }
);
console.log(
"howToMakeIncremental([1, 4, 10, 4, 2]) ?..",
howToMakeIncremental([1, 4, 10, 4, 2]) // { isAchievable: false }
);
.as-console-wrapper { min-height: 100%!important; top: 0; }
Creating a new array seems overkill. I would first define a function that verifies at which index a given array violates being incremental.
Then check if there is a second violation after that. If so, return false.
With just one violation, return true when it occurs between the first two or last two values in the array.
In all other cases, verify that removing either of the two involved values resolves the violation.
Code:
// Return the index where the value is not greater than its predecessor
function violation(a, start=0) {
for (let i = start + 1; i < a.length; i++) {
if (a[i - 1] >= a[i]) return i;
}
return 0;
}
function solution(a) {
let i = violation(a);
return !i || !violation(a, i) && (i==1 || i==a.length-1
|| a[i-2] < a[i] || a[i-1] < a[i+1]);
}
//TEST CASES
let tests = [
[1, 2, 3, 4, 5, 3, 5, 6],
[40, 50, 60, 10, 20, 30],
[1, 2, 3, 4, 3, 6],
[1, 4, 10, 4, 2]
];
for (let test of tests) {
console.log(solution(test));
}
There is nothing with your logic just remove the first return
function solution(sequence) {
let newArr = [];
for(let i = 0; i < sequence.length - 1; i++) {
sequence[i] < sequence[i+1] ? newArr.push(true)
: sequence[i+1] < sequence[i-1] ? newArr.push('very false')
:newArr.push(false)
}
// return newArr
return (newArr.filter(i => i === false).length) > 1 || ( (newArr.includes('very
false')) && (newArr[newArr.length - 1] !== 'very false')) || (
newArr.includes(false) && newArr.includes('very false')) ? false : true;
}
//TEST CASES
let one = [1, 2, 3, 4, 5, 3, 5, 6]
let two = [40, 50, 60, 10, 20, 30]
let three = [1, 2, 3, 4, 3, 6]
let four = [1, 4, 10, 4, 2]
console.log(solution(one));
console.log(solution(two));
console.log(solution(three));
console.log(solution(four));

Check if at least two elements in an array are greater than zero - JavaScript/Typescript [duplicate]

This question already has answers here:
How to count certain elements in array?
(27 answers)
Closed 3 years ago.
Is there a smart way to find out if there are at least two values greater than 0 in an array and return true? And false in the opposite case?
(hypothetical and wrong example using some):
const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];
const cond = (el) => el > 0 && somethingElseMaybe;
console.log(a.some(cond)); // print true
console.log(b.some(cond)); // print false
console.log(c.some(cond)); // print false
Use filter() to remove values below zero and then check if the length of resulting array is greater than or equal to two
const twoGreaterThanZero = arr => arr.filter(x => x > 0).length >= 2;
console.log(twoGreaterThanZero([9, 1, 0])) //true
console.log(twoGreaterThanZero([0, 0, 0])) //false
console.log(twoGreaterThanZero([5, 0, 0])) //false
To avoid wasted effort, you should stop the checking as soon as the condition is met. I think this meets your requirement.
function twoGreaterThanZero(arr) {
let counter = 0
for(let x of arr) {
if(x > 0 && (++counter > 1)) return true
}
return false
}
const a = [9, 1, 0]
const b = [0, 0, 0]
const c = [5, 0, 0]
console.log(twoGreaterThanZero(a)) // print true
console.log(twoGreaterThanZero(b)) // print false
console.log(twoGreaterThanZero(c)) // print false
If you don't want to iterate over the entire array you can use a loop and break out of it early once your condition is satisfied. I think the answer that uses filter is more elegant, but if you're list is insanely large you might see a benefit from not iterating the entire thing.
I broke this function into it's basic parts and created a curried version.
The question is "are there 2 or more values greater than 0 in the array". But it can be boiled down to "are there X or more values that pass comparator"?
const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];
const quantityCompare = compare => quantity => arr => {
let count = 0;
for (let i = 0; i < arr.length; i += 1) {
if (compare(arr[i])) count += 1;
if (count >= quantity) return true;
}
return false;
};
const twoElementsGreaterThanZero = quantityCompare(x => x > 0)(2);
console.log(twoElementsGreaterThanZero(a)); // true
console.log(twoElementsGreaterThanZero(b)); // false
console.log(twoElementsGreaterThanZero(c)); // false
One more for fun, you can use Array.some (an Array.forEach you can break out of) instead of the for loop:
const a = [9, 1, 0];
const b = [0, 0, 0];
const c = [5, 0, 0];
const quantityCompare = compare => quantity => arr => {
let count = 0;
return arr.some(el => {
if (compare(el)) count += 1;
if (count >= quantity) return true;
})
}
const twoElementsGreaterThanZero = quantityCompare(x => x > 0)(2);
console.log(twoElementsGreaterThanZero(a)); // true
console.log(twoElementsGreaterThanZero(b)); // false
console.log(twoElementsGreaterThanZero(c)); // false
If you are in a situation where doing things like this is frequently necessary, you can always create your own facility for producing predicate functions. In this case, you could start with a master function to create functions that return true or false if an array contains a minimum number of values that satisfy a condition:
function minimumSatisfy(condition, minimum) {
return function(array) {
for (var i = 0, c = 0; i < array.length && c < minimum; i++) {
if (condition(array[i]))
c++;
}
return c >= minimum;
}
}
To use that for checking your particular case, use it to make a specific function:
let twoGtZero = minimumSatisfy(v => v > 0, 2);
Now you can test any array with that predicate:
if (twoGtZero(someArray)) {
// ...
}
Of course if you've only got one place in your code that requires such a test, it would be silly to do this.
Try that
var a = [9, 1, 0]
var b = [0, 0, 0]
var c = [5, 0, 0]
function atLeastTwoEntries(arr, entrie) {
return arr.indexOf(entrie) !== arr.lastIndexOf(entrie)
}
console.log(atLeastTwoEntries(a, 0))
console.log(atLeastTwoEntries(b, 0))
console.log(atLeastTwoEntries(c, 0))
Try this,
console.log(a.filter(s => s > 0).length >= 2); // print true
console.log(b.filter(s => s > 0).length >= 2); // print false
console.log(c.filter(s => s > 0).length >= 2); // print false

Updating operation from sum to subtract or viceversa depending on a given value

I need to sum or subtract the values of an array.
For example:
[1, 5, 10] should be represented as: 1 + 5 + 10 = 16.
And [1, 5, -1, 10, 5] should be: 1 + 5 - 10 - 5 the -1 number indicates subtraction or sum depending where the -1 is. The 1st -1 will indicate subtraction, the second one -1 indicates that everything is getting back to a regular sum as everything was in the beginning, the 3rd will be subtraction again, and so on.
Now look how it should be with 2 -1s: [1, 5, -1, 10, 5, -1, 5, 5], it
should be represented as: 1 + 5 - 10 - 5 + 5 + 5, got it ?
So, everything should be sum up until the array contains a -1 so it changes to subraction, if there is another -1 the operation should change to be a sum. And so on, every time there is a new '-1' the operation changes to the contrary it was before.
I am doing that calculation like this:
function calculate (){
logingValues();
var total = 0;
var shouldSubtract = false;
for (var i = 0; i < arrayOfNumbers.length; i++) {
if (arrayOfNumbers[i] === "") continue;
var currentNumber = parseInt(arrayOfNumbers[i], 10);
if(isNaN(currentNumber)) {
currentNumber = 0;
}
if (currentNumber === -1) {
shouldSubtract = true;
} else {
if (shouldSubtract) {
total -= currentNumber;
shouldSubtract = false;
} else {
total += currentNumber;
}
}
}
caculationEffect(total);
}
And here is the whole code
Any suggestions?
You could use a variable for the deciding if to add or subtract the actual value.
function sum(array){
var negative;
return array.reduce(function (a, b) {
if (b === -1) {
negative = !negative;
return a;
}
return negative ? a - b : a + b;
}, 0);
}
console.log(sum([1, 5, 10]));
console.log(sum([1, 5, -1, 10, 5]));
console.log(sum([1, 5, -1, 10, 5, -1, 5, 5]));
Here is my short Array.prototype.reduce solution:
[1, 5, -1, 10, 5, -1, 5, 5].reduce(function(ctx, x) {
if (x === -1) // if the current value is -1 ...
ctx.sign *= -1; // - change the sign
else // otherwise ...
ctx.sum += x * ctx.sign; // - transform according to the sign
return ctx; // return context
}, { sign: 1, sum: 0 }).sum;
You can use one var and change true/false each time element in array is -1
function sum(a) {
var check = true, result = 0;
a.forEach(function(e) {
//If e is negative number and check is true change check to false
if (e < 0 && check == true) {
check = false;
//If e is negative number and check is false change check to true
} else if (e < 0 && check == false) {
check = true;
}
//If e is positive number and check is true add to result
if (e > 0 && check == true) {
result += e;
//If e is positive number and check is false subtract of result
} else if (e > 0 && check == false) {
result -= e;
}
})
return result;
}
console.log(sum([1, 5, 10]));
console.log(sum([1, 5, -1, 10, 5]));
console.log(sum([1, 5, -1, 10, 5, -1, 5, 5]));
To add another to the mix, not because it's better, but because it's possible :) (although this version does depend on ES6 )
function calc(arr){
var [v,...rest] = arr; //assign v to the first value, rest to the following values
var sr = rest.length ? calc(rest) : 0; //calc sum of rest
return v === -1 ? -sr : v + sr; //if value === -1, return sum of rest with reversed sign, otherwise return sum
}
console.log(calc([1, 5, 10]));
console.log(calc([1, 5, -1, 10, 5]));
console.log(calc([1, 5, -1, 10, 5, -1, 5, 5]));

Best practice when sorting an array in pure javascript, if I have to send one group to the back

If I have the following array:
[0, 1, 3, 0, 4, 2]
And I'd like to sort it ascending order, barring zeros which I need on the end:
[1, 2, 3, 4, 0, 0]
Bear in mind I don't have access to underscore or linq.js for this solution.
My current solution works, but feels quite heavy, long, and not very elegant. Here's my code:
function sortNumbers(numbers) {
var zeroNumbers = [];
var notZeroNumbers = [];
for (var i = 0; i < numbers.length; i++) {
if (numbers[i] === 0) {
zeroNumbers.push(numbers[i]);
} else {
notZeroNumbers.push(numbers[i]);
}
}
var sortedNumbers = notZeroNumbers.sort(function (a, b) {
return parseFloat(a) - parseFloat(b);
});
for (var x = 0; x < zeroNumbers.length; x++) {
sortedNumbers.push(zeroNumbers[x]);
}
return sortedNumbers;
}
Can I improve on this solution?
This is not related to this question, but I was searching for "pure sort javascript" and this is the first answer.
Because sort mutates the original array, the best practice when sorting an array is to clone it first.
const sortedArray = [...array].sort(/* optional comparison function*/)
simply try
var output = [0, 1, 3, 0, 4, 2].sort(function(a, b) {
a = a || Number.MAX_SAFE_INTEGER; //if a == 0 then it will be a falsey value and a will be assigned Number.MAX_SAFE_INTEGER
b = b || Number.MAX_SAFE_INTEGER;
return a - b;
});
console.log(output)
var arr = [0, 1, 3, 0, 4, 2, 9, 8, 7, 0];
arr.sort(function (left, right) {
return left == right ? 0 : (left === 0 ? 1 : (left < right ? -1 : 1));
});
console.log(arr)
This will always put zeroes at the end regardless of the size of the number.
Another alternative solution using Array.sort, Array.splice and Array.push functions:
var arr = [0, 1, 3, 0, 4, 2];
arr.sort();
while(arr[0] === 0) { arr.splice(0,1); arr.push(0); }
console.log(arr); // [1, 2, 3, 4, 0, 0]
You can use sort for this, which takes a closure/callback.
var sortedArray = [0, 1, 3, 0, 4, 2].sort(function(currentValue, nextValue) {
if(currentValue === 0) {
return 1;
} else {
return currentValue - nextValue;
}
});

Categories

Resources