How do I avoid a potential infinite loop? - javascript

I cannot understand why my function exceeds time limit and why it can go into an infinite loop. Is there an edge case I might be overlooking?
Here is the problem description:
Given a sorted array of distinct integers and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
var searchInsert = function(nums, target) {
if (target > nums[nums.length - 1]) { // If target is greater
return nums.length; // than the largest element
};
let leftIndex = 0; // implementing binary search
let rightIndex = nums.length - 1;
while (leftIndex != rightIndex) {
let pivot = Math.round((rightIndex + leftIndex) / 2);
if (target == nums[pivot]) {
return pivot;
} else if (target < nums[pivot]){
rightIndex = pivot - 1;
} else {
leftIndex = pivot + 1;
}
};
return target <= nums[leftIndex] ? leftIndex : leftIndex + 1;
};

You could use a condition which really stops the loop, for example by checking left and right and if left is greater than right exit the loop.
while (leftIndex < rightIndex) {
Another part is to floor the pivot index, either by using Math.floor or by >> right shift.
const pivot = (rightIndex + leftIndex) >> 1; // right shift by one bit
This prevents to omit some indices and produces predictable results.
To check all use an array with even and odd items and check every value of the array.
var searchInsert = function(nums, target) {
let leftIndex = 0;
let rightIndex = nums.length - 1;
if (target > nums[rightIndex]) return nums.length;
while (leftIndex < rightIndex) {
const pivot = (rightIndex + leftIndex) >> 1;
if (target === nums[pivot]) return pivot;
if (target < nums[pivot]) rightIndex = pivot - 1;
else leftIndex = pivot + 1;
};
return target <= nums[leftIndex] ? leftIndex : leftIndex + 1;
};
console.log(searchInsert([0, 1, 2, 3, 4, 5], -0.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 0));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 0.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 1));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 1.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 2));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 2.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 3));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 3.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 4));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 4.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 5));
console.log(searchInsert([0, 1, 2, 3, 4, 5], 5.5));
console.log('--');
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], -0.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 0));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 0.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 1));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 1.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 2));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 2.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 3));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 3.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 4));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 4.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 5.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 6));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 6.5));
console.log(searchInsert([0, 1, 2, 3, 4, 5, 6], 7));
.as-console-wrapper { max-height: 100% !important; top: 0; }

const array = [1, 2, 6, 8, 10, 16, 18, 20, 33, 55]
function findTarget(target){
if(array.includes(target)){
return "Target was found at index : " + array.indexOf(target)
}
if(array[0] > target)
return "Target should be inserted at index : " + 0
for(let i = 0; i < array.length; i+=1){
if(array[i] < target && array[i + 1] > target){
return "Target should be inserted at index : " + (i+1)
}
}
return "Target should be inserted at index : " + array.length
}
console.log(findTarget(8))
console.log(findTarget(9))
console.log(findTarget(60))
console.log(findTarget(0))

Related

Function that takes an array and returns elements inside rotated n spaces in js

Create a function named "rotate" that takes an array and returns a new one with the elements inside rotated n spaces.
If n is greater than 0 it should rotate the array to the right. If n is less than 0 it should rotate the array to the left. If n is 0, then it should return the array unchanged.
Example:
var data = [1, 2, 3, 4, 5];
rotate(data, 1) // => [5, 1, 2, 3, 4]
rotate(data, 2) // => [4, 5, 1, 2, 3]
rotate(data, 3) // => [3, 4, 5, 1, 2]
rotate(data, 4) // => [2, 3, 4, 5, 1]
rotate(data, 5) // => [1, 2, 3, 4, 5]
rotate(data, 0) // => [1, 2, 3, 4, 5]
rotate(data, -1) // => [2, 3, 4, 5, 1]
rotate(data, -2) // => [3, 4, 5, 1, 2]
rotate(data, -3) // => [4, 5, 1, 2, 3]
rotate(data, -4) // => [5, 1, 2, 3, 4]
rotate(data, -5) // => [1, 2, 3, 4, 5]
Furthermore the method should take ANY array of objects and perform this operation on them:
rotate(['a', 'b', 'c'], 1) // => ['c', 'a', 'b']
rotate([1.0, 2.0, 3.0], 1) // => [3.0, 1.0, 2.0]
rotate([true, true, false], 1) // => [false, true, true]
Finally, the rotation shouldn't be limited by the indices available in the array. Meaning that if we exceed the indices of the array it keeps rotating.
Example:
var data = [1, 2, 3, 4, 5]
rotate(data, 7) // => [4, 5, 1, 2, 3]
rotate(data, 11) // => [5, 1, 2, 3, 4]
rotate(data, 12478) // => [3, 4, 5, 1, 2]
You could basically do this with a while loop and increment or decrement based on the number parameter, if its positive or negative.
function rotate(data, n) {
const output = [...data]
if (n === 0) {
return data
}
const neg = n < 0
const last = output.length - 1
const toIndex = neg ? last : 0
const index = neg ? 0 : last
while ((neg ? n++ : n--) !== 0) {
output.splice(toIndex, 0, output.splice(index, 1)[0])
}
return output
}
var data = [1, 2, 3, 4, 5];
console.log(rotate(data, 2)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, 3)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, 4)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, 5)) // => [1, 2, 3, 4, 5]
console.log(rotate(data, -1)) // => [2, 3, 4, 5, 1]
console.log(rotate(data, -2)) // => [3, 4, 5, 1, 2]
console.log(rotate(data, -3)) // => [4, 5, 1, 2, 3]
console.log(rotate(data, -4)) // => [5, 1, 2, 3, 4]
console.log(rotate(data, -5)) // => [1, 2, 3, 4, 5]
console.log(rotate(['a', 'b', 'c'], 1))
console.log(rotate([true, true, false], 1))

Get 3x3 blocks from 9x9 2d array as String

I am learning Javascript and currently found myself with the following problem. I need to get each individual 3x3 block of a 9x9 2d array as a string, separated by commas.
What I mean is, for example, let's say I have the following array:
var 2dArray = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9] ]
The result should be something like 535671192,678195342, 912348657, ... and so on, until the string is made of all the 3x3 blocks.
I thought that making nested for loops would be the best approach, but got confused along the way and I would appreciate your help.
Thank you.
You can use two loops to iterate over the positions of all the possible top left corners and another two loops to get all the elements in that square.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
for (let i = 0; i < 9; i += 3) {
for (let j = 0; j < 9; j += 3) {
let curr = "";
for (let k = 0; k < 3; k++) {
for (let l = 0; l < 3; l++) {
curr += arr[i + k][j + l];
}
}
res.push(curr);
}
}
console.log(res);
The issue can also be solved by loops but it's good practice to solve it using the Array.map() function.
let arrayRow = "";
const resultArray = Array2d.map((element, index) => {
return arrayRow + element.map((element, i) => {
return element.toString();
});
});
you should try like this too.
var arr = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]
];
let res = [];
let i = 0,j = 0;
let justOneStr = "";
while(i < 9 && j < 9){
justOneStr += arr[i][j];
if(i % 3 == 2 && j % 3 == 2){
res.push(justOneStr);
justOneStr="";
}
if((j % 9 == 8 || j % 3 == 2) && i % 3 != 2){
j -= 3;
i += 1;
}
else if(j % 9 == 8 && i % 3 == 2){
j -= 9;
i += 1;
}
else if(i % 3 == 2 && j % 3 == 2){
i -= 2;
}
j++;
}
console.log(res);
Here's a fairly straightforward nested reduce() that returns an array of matrices of the specified size. It touches each element once, and uses the coordinates in the passed matrix to determine which sub-matrix and sub-matrix row to accumulate into.
const
matrix = [
[5, 3, 5, 6, 7, 8, 9, 1, 2],
[6, 7, 1, 1, 9, 5, 3, 4, 8],
[1, 9, 2, 3, 4, 2, 5, 6, 7],
[8, 5, 9, 7, 6, 1, 4, 2, 3],
[4, 2, 6, 5, 5, 3, 7, 9, 1],
[7, 1, 3, 1, 2, 4, 8, 5, 6],
[9, 6, 1, 5, 3, 7, 2, 8, 4],
[2, 8, 7, 5, 1, 9, 6, 3, 5],
[3, 4, 5, 6, 8, 6, 1, 7, 9]],
subdivide = (matrix, width, height) => {
return matrix.reduce((acc, row, i) => {
row.reduce((_acc, x, j, row) => {
const grid = Math.floor(j / width) + Math.floor(i / height) * (Math.ceil(row.length / width));
const gridRow = i % height;
_acc[grid] ??= [];
(_acc[grid][gridRow] ??= []).push(x);
return _acc;
}, acc)
return acc;
}, [])
},
subdividedmatrix = subdivide(matrix, 3, 3);
// log submatrices
subdividedmatrix.forEach(m => console.log(JSON.stringify(m)));
// map to strings
console.log(subdividedmatrix.map(submatrix => submatrix.flat().join('')))
.as-console-wrapper { max-height: 100% !important; top: 0; }

Passing an array to a function parameter and getting values from nested array

I got stuck while practicing credit card checker practice.
My code:
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5]
// Add your functions below:
const validateCred = (array)=> {
let tempArrSub = []; //Holds values of the 9 subtracted from doubled elements bigger than 9
let tempArr = array; //Copies the values of the array passed into parameters
tempArr.pop();
tempArr.reverse();
for (let i = tempArr.length-1; i >=0; i-=2){ //Doubles every two elements from right to left
tempArr[i] *= 2;
}
for (let k = 0; k < tempArr.length; k++) { //Subtract 9 from every second element (right to left) if bigger than 9
if (tempArr[k] > 9){
tempArrSub.push(tempArr[k] - 9);
}
else {
tempArrSub.push(tempArr[k]);
}
}
let tempArrSum = 0;
for (let m = 0; m < tempArrSub.length; m++){ //Calculates the sum of all elements in the array
tempArrSum += tempArrSub[m];
}
tempArrSum += array.pop(); //Adds the last digit of initial array to the sum
if (tempArrSum % 10 === 0) { //Returns true if the sum is divisible by 10
return true;
}
else {
return false;
}
} //End Of Function
const findInvalidCards = (nestedArray) => {
let invalidCards = [];
let validCards = [];
for (let a = 0; a < nestedArray.length; a++){
if ( validateCred(nestedArray[a]) == true ) {
validCards.push(nestedArray[a]);
}
else {
invalidCards.push(nestedArray[a]);
}
}
console.log("Invalid cards: \n" + invalidCards);
console.log("Valid cards: \n" + validCards);
}
I checked all arrays one by one passing as an argument to validateCred() function. It's working and returning true or false for each credit card.
In order to automate process I wanted findInvalidCards() to find valid or invalid cards by calling validateCred() function inside itself and returning boolean value for each card.
Here I got stuck. Because it is returning true for the 1st card and false for the remaining cards. I've been playing with the code for the whole day, but I could not move forward. I rely on your help. Thanks in advance
I don't know if is it helpful to you or not. But I rewrite your code with an optimal way.
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8]
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9]
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6]
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5]
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6]
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5]
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3]
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4]
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5]
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4]
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9]
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3]
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3]
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3]
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
isValidCard = (array) => {
let copy = [...array];
const last = copy.pop();
copy.reverse();
copy = copy.map((dig, i) => ((i % 2 === 0 ? dig * 2 : dig)));
copy = copy.map(dig => (dig > 9 ? dig - 9 : dig));
const sum = copy.reduce((acc, curr) => acc + curr);
return ((sum + last) % 10 === 0);
}
findInvalidCards = (array) => {
const validList = [];
const invalidList = [];
array.forEach(card => {
if (isValidCard(card)) {
validList.push(card);
} else {
invalidList.push(card);
}
});
console.log('valid cards', validList);
console.log('invalid cards', invalidList);
}
findInvalidCards(batch);
I think your issue is this line:
let tempArr = array; //Copies the values of the array passed into parameters
According to your comment you want to copy the array, but just assigning it to another variable does not copies it. In order to copy just so something like this:
let copy = array.slice(0);
/* or (will not work for large arrays) */
let copy = [...array];
// All valid credit card numbers
const valid1 = [4, 5, 3, 9, 6, 7, 7, 9, 0, 8, 0, 1, 6, 8, 0, 8];
const valid2 = [5, 5, 3, 5, 7, 6, 6, 7, 6, 8, 7, 5, 1, 4, 3, 9];
const valid3 = [3, 7, 1, 6, 1, 2, 0, 1, 9, 9, 8, 5, 2, 3, 6];
const valid4 = [6, 0, 1, 1, 1, 4, 4, 3, 4, 0, 6, 8, 2, 9, 0, 5];
const valid5 = [4, 5, 3, 9, 4, 0, 4, 9, 6, 7, 8, 6, 9, 6, 6, 6];
// All invalid credit card numbers
const invalid1 = [4, 5, 3, 2, 7, 7, 8, 7, 7, 1, 0, 9, 1, 7, 9, 5];
const invalid2 = [5, 7, 9, 5, 5, 9, 3, 3, 9, 2, 1, 3, 4, 6, 4, 3];
const invalid3 = [3, 7, 5, 7, 9, 6, 0, 8, 4, 4, 5, 9, 9, 1, 4];
const invalid4 = [6, 0, 1, 1, 1, 2, 7, 9, 6, 1, 7, 7, 7, 9, 3, 5];
const invalid5 = [5, 3, 8, 2, 0, 1, 9, 7, 7, 2, 8, 8, 3, 8, 5, 4];
const invalidCredit = [invalid1, invalid2, invalid3, invalid4, invalid5]
// Can be either valid or invalid
const mystery1 = [3, 4, 4, 8, 0, 1, 9, 6, 8, 3, 0, 5, 4, 1, 4];
const mystery2 = [5, 4, 6, 6, 1, 0, 0, 8, 6, 1, 6, 2, 0, 2, 3, 9];
const mystery3 = [6, 0, 1, 1, 3, 7, 7, 0, 2, 0, 9, 6, 2, 6, 5, 6, 2, 0, 3];
const mystery4 = [4, 9, 2, 9, 8, 7, 7, 1, 6, 9, 2, 1, 7, 0, 9, 3];
const mystery5 = [4, 9, 1, 3, 5, 4, 0, 4, 6, 3, 0, 7, 2, 5, 2, 3];
// An array of all the arrays above
const batch = [valid1, valid2, valid3, valid4, valid5, invalid1, invalid2, invalid3, invalid4, invalid5, mystery1, mystery2, mystery3, mystery4, mystery5];
// Add your functions below:
const validateCred = (arr) => {
let reversedArr = arr.reverse();
let oddOccurrences = [];
reversedArr.forEach((value, i) => i % 2 ? oddOccurrences.push(value *= 2) : oddOccurrences.push(value));
const checking = oddOccurrences.map((greater) => (greater > 9 ? (greater -= 9) : greater));
const sum = checking.reduce((acc, num) => {
return acc + num
}, 0)
// Conditional check
if (sum % 10 === 0)
return 'valid'
else return 'invalid'
}
console.log(validateCred([4, 5, 3, 9, 6, 8, 9, 8, 8, 7, 7, 0, 5, 7, 9, 8]));
findInvalidCards = (newArr) => {
const invalidList = [];
const validList = [];
for (let i = 0; i < newArr.length; i += 15) {
// inner loop
for (let j = 0; j < newArr.length; j++) {
validateCred(newArr[j]) === 'invalid' ? invalidList.push(newArr[j]) : validList.push(newArr[j]);
}
};
console.log(invalidList)
}
findInvalidCards(batch);

How to compare multidimensional array by columns

I am creating a function to compare items in a multidimensional array of length 6. I compare from bottom to top and left to right. If the first elements (index 0) are as follows i[0][5] > i[0][4] > i[0][3] > i[0][2] > i[0][1] > i[0][0] it returns false and if there is only at least one element that does not respect the rule above it should return false.
When I try to use for loop, the program only returns 1 result not all expected ones.
let multidimArr = [
[1, 2, 3, 2, 1, 1]
[2, 4, 4, 3, 2, 2]
[5, 5, 5, 5, 4, 4]
[6, 6, 7, 6, 5, 5]
[4, 7, 6, 8, 7, 6]
[4, 9, 6, 7, 8, 9]
];
function compare() {
for (var i=0, len=multidimArr.length; i<len; i++) {
for (var j=0, len2=multidimArr[i].length; j<len2; j++) {
if( i <= 0 ) continue;
if ( multidimArr[i][j] < multidimArr[i - 1][j] ) {
return false
);
} else if( multidimArr[i][j] > multidimArr[i - 1][j] ){
return true;
}
}
console.log('the status is [' + compare() + ']');
For this code the expected result is false for the first column, true for the second, false for the 3rd, true for 4th, false for 5th and true for last column.
Unfortunately it only return false.
You could reduce the array and take true for the first row and then check the last and actual value and respect the last check.
function check(array) {
return array.reduce((r, a, i, { [i - 1]: b }) => a.map((v, j) => i
? r[j] && b[j] < v
: true
), []);
}
var array = [[1, 2, 3, 2, 1, 1], [2, 4, 4, 3, 2, 2], [5, 5, 5, 5, 4, 4], [6, 6, 7, 6, 5, 5], [4, 7, 6, 8, 7, 6], [4, 9, 6, 7, 8, 9]];
console.log(check(array));

Easiest way to derive subset array of highest 10 values?

In javascript I have an array as follows:
var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
And I am interested in finding a way (within one loop, not multiple) to derive a subset array of the highest 10 values, where the previous position of the value is the 'key' (so simulating a Map object):
eg:
var fooTopTen = [[4, 128], [18, 128], [25, 60], [27, 28], [10, 27], [37, 27], [15, 21], [9, 18], [14, 18], [23, 18]];
My previous answer used a reverse index table, but contained some bugs - which are now fixed - and was harder to understand than the following code.
This is actually the slowest of all solutions given in the answers - for maximum performance, check my other answer.
var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
var fooTopTen = [];
// add index to values
for(var i = 0, len = foo.length; i < len; ++i)
fooTopTen.push([i, foo[i]]);
// sort first by value (descending order), then by index (ascending order)
fooTopTen.sort(function(t1, t2) {
return t2[1] - t1[1] || t1[0] - t2[0];
});
// shorten array to correct size
fooTopTen.length = 10;
// output top ten to check result
document.writeln('[[' + fooTopTen.join('], [') + ']]');
The second part of the comparison function (the one comparing the indices) is not needed, as sort() is stable in most implementations (this isn't required by ECMA according to MDC). I'll leave it in as an example to how sorting with multiple requirements can be done...
This runs once through the main array it searches, inserting items at the appropriate place in the results array:
function top10(arr) {
var results = [[0,Number.MAX_VALUE],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0],[0,0]];
for (var i=0; i<arr.length; i++) {
// search from back to front
for (var j=9; j>=0; j--) {
if (arr[i] <= results[j][1]) {
if (j==9)
break;
results.splice(j+1, 0, [i, arr[i]]);
results.pop();
break;
}
}
}
return results.slice(1);
}
For large arrays this should even be rather fast, since most times the inner loop should only do one iteration.
Here's the de-bugged version of my previous answer using an index table. I did a little benchmarking and for the input given in the question, this solition will be faster than anything else which has been suggested in this thread till now:
var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
var indexTable = {}, uniqueValues = [];
// --- build reverse index table, find unique values
for(var i = foo.length; i--; ) {
var value = foo[i];
if(indexTable.hasOwnProperty(value))
indexTable[value].push(i);
else {
indexTable[value] = [i];
uniqueValues.push(value);
}
}
// --- sort unique values in ascending order
uniqueValues.sort(function(i1, i2) {
return i1 - i2;
});
// --- find ten greatest values
var fooTopTen = [], k = 0;
for(var i = uniqueValues.length; k < 10 && i--; ) {
var value = uniqueValues[i],
indices = indexTable[value];
for(var j = indices.length; k < 10 && j--; )
fooTopTen[k++] = [indices[j], value];
}
// --- output result
document.writeln('[[' + fooTopTen.join('], [') + ']]');
var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
var index = 0;
var result = foo.map( function(a){ return [index++, a]; } )
.sort( function(a,b){ return (a[1] < b[1]); } )
.splice( 0, 10 );
document.write(result.join( ' ' ));
If foo is very large compared to the size of result required, it may be quicker to iterate over foo insertion-sorting each element into result as we come across it.
// Sorting method
function sortNumber(a, b) {
return a - b;
}
// Find the offset of an element in array
function findOffset(element, array) {
for (var i = 0; i < array.length; i++) {
if (array[i] == element) {
// Make sure we don't find it again
array[i] = null;
return i;
}
}
}
var foo = [2, 2, 4, 4, 128, 2, 2, 1, 4, 18, 27, 16, 2, 1, 18, 21, 5, 1, 128, 1, 2, 2, 1, 18, 12, 60, 2, 28, 1, 17, 2, 3, 4, 2, 2, 2, 1, 27, 2, 17, 7, 2, 2, 2, 5, 1, 2, 4, 7, 1, 2, 1, 1, 1, 2, 1, 5, 7, 2, 7, 6, 1, 7, 1, 5, 8, 4];
// Copies
var bar = foo.slice();
var baz = foo.slice();
var fooTopTen = new Array(10);
// Sort
bar.sort(sortNumber).reverse();
// Create the results
for (var i = 0; i < 10; i++) {
fooTopTen[i] = new Array(2);
fooTopTen[i][0] = findOffset(bar[i], baz);
fooTopTen[i][1] = bar[i];
}
computer-science-y answer:
problem statement: Given a large array X of length N, and a small number m < N (here m=10), produce an array Y of length m where each element of Y contains the pair {i,X[i]} such that the set of X{i} are the m largest elements of X.
If m is much smaller than N, then loop over elements of X and sort them into Y, discarding pairs to maintain at most m elements. (i.e. as moonshadow mentioned)
Sorting X will cost you O(N log N) elements. Iterating over X and sorting into Y should cost you only O(N log m) elements.

Categories

Resources