PROBLEM
I'm working on a codewars problem where I'm supposed to find the peaks of an array. For example, [4, 9, 3, 2, 1] => 9 would be considered a peak because the values before and after it are lower than it.
I've been able to identify the peak by simply writing a for loop and an if statement where if (a[i] > a[i+1] && a[i] < a[i-1]) return a[i]
In some instances, peak/plateaus can happen when the highest number is repeated. For instance [3, 6, 9, 9, 9, 9, 7]. Since the plateaus length can vary to any degree, I want to figure out the index for when the 9 stops repeating (index stop = 5) or even when the new value starts (7).
ATTEMPTS
I wanted to try to use a for loop, but it seems like I can only use it for values that come immediately after one another. I tried looking into the .repeat function, but it seems to only create and not identify the index of existing repetitions. New Set will show me the unique values, but it will alter the original array.
I'm not sure how I would implement .length.
.lastIndexOf won't work either because I don't want my function to pick up values that are the same as the peak but are located later in the array. For example [3,4,9,9,9,2,9,10,8] => The first 9 would be a peak, but the last nine would not.
I don't want to mutate the array by taking out existing values from it because I'm supposed to return the indexes of peak. Mutating it will change the index. Non-regex methods would be preferable!
I'd appreciate any input! Thanks!
Related
I've read in documentation about compare function's work. This callback function can have 2 parameters. There are 3 "if" for them:
If compareFunction(a, b) returns a value > than 0, sort b before a.
If compareFunction(a, b) returns a value < than 0, sort a before b.
If compareFunction(a, b) returns 0, a and b are considered equal.
So, as far as I see, if compare function returns a value less than zero, compare algorithm do nothing (a and b stay in the same places). And if this function returns a value more than zero, a and b switches (b goes first).
Okay, that's understandable. But why my code below works like that?
let arr1 = [9, 3, 6, 7, 1];
console.log(arr1.sort((a, b) => 1)); //1 > 0 -> compare function should switch elements
let arr2 = [9, 3, 6, 7, 1];
console.log(arr2.sort((a, b) => -1)); //-1 < 0 -> compare function shouldn't switch elements
Your interpreation of the docs is wrong.
You say
-1 means elements should stay in the same place.
That's wrong, the docs just state that -1 means a should be sorted before b.
Depending on the underlying sorting algorithm, there is no guarantee whatsoever that, when calling the comparefunction with parameters a and b that a is currently before b in the array. Ie imagine an array [1,2,3]. It may be possible that the compare function is called with parameters (3, 1) or (1,3). But if you return -1 in the first case, 1 and 3 will indeed switch positions. And vice versa, if you return 1 in the second case, 1 and 3 will again switch places.
EDIT
Different browser implement sort differently. For instance if you execute the following snippet in chrome and in firefox you will get different results.
var arr = [1,2,3,4,5,6,7,8,9];
arr.sort((a,b) => {
console.log(`${a} ${b}`);
return 1;
})
console.log(arr);
For instance in my current chrome (Version 94.0.4606.61 on Windows), b will be less than a for all calls of the compare function, and thus returning 1 from the compare function would mean, to sort b before a which is already the case. Thus nothing will change.
Wheras in my firefox (Version 92.0 on Windows) b will be greater than a for all calls of the compare function. And thus, returning 1 from the compare function would again mean to sort b before a, which is not currently the case. Thus, the array will be reversed ...
Other runtimes with again a different implementation of sort may again lead to other totally unpredictable results ...
If the compare function returns the wrong answer when asked the fundamental question which value is less than the other, why wouldn't you expect the wrong answer from the function that depends on it?
The sort algorithm probably makes the equivalent of two passes before it is done, and ends up returning the values back to its place on the second pass.
I say equivalent - it might be going through once, but on the lower index elements it sorts it one way, and on the higher elements it goes the other way.
For the second case, it considers the top elements sorted, and then the bottom elements it thinks it has to switch.
But sorts all work differently. A merge sort might depend on how many times it is divisible by 2. A quick sort might depend on the pivot position. An insertion sort might depend on number of elements being even or odd.
So philosophy aside, the fundamental issue is the following:
compare(1, 2) = 1, so switch.
compare(2, 1) = 1, so switch.
If you wanted a reason your bad compare function made sort behave the way it did, that is why.
If you actually wanted it to reverse the sort, then you want something like:
function compare(int a, int b)
{
if (a < b) return 1;
if (a > b) return -1;
return 0;
}
I have an array of arrays like this, const array = [[1,5],[7,9],[10,14]]; I need to check to see if the arrays are in order.
Basically, for the provided array, I need to compare the first array's second value, (5), with the second array's first value, (7), which I would then use to invalidate a form.
If the arrays or in order, const array = [[1,5],[6,9],[10,14]]; it returns false, it passes validation, if they aren't, validation fails and it returns true.
So far, I've done something like this.
const arrayIdxZeroValues = [];
const arrayIdxOneValues = [];
array.forEach((arr,idx) => {
arrayIdxZeroValues.push(arr[0])
arrayIdxOneValues.push(arr[1])
})
which separates the values fine. I then thought about using .shift() to remove the first value of arrayIdxZeroValues since it will never need to be compared, but I feel this is hacky and I'm not sure it's the right approach from here. Maybe .reduce() to compare the output arrays, but I haven't been able to get it to work right.
Any guidance would be much appreciated.
Thanks
Create an array that starts from the 2nd sub-array using Array.slice(). Use Array.some() and check if the 2nd item of the current sub-array is equal or less the 2nd item of the sub-array at the current index i of the original array. In this way you compare the 2nd with the 1st, the 3rd with the 2nd, and so on.
false - means the validation passed
true - means validation failed
const isFailed = arr => arr.slice(1)
.some(([n], i) => n !== arr[i][1] + 1)
console.log(isFailed([[1,5],[6,9],[10,14]])) // false
console.log(isFailed([[1,5],[7,9],[10,14]])) // true
You could check the actual value agains the last value of the previous array plus one and omit the check for the first inner array.
const
inOrder = array => array.every(([v], i, a) => !i || a[i - 1][1] + 1 === v);
console.log(inOrder([[1, 5], [7, 9], [10, 14]]));
console.log(inOrder([[1, 5], [6, 9], [10, 14]]));
Now I would like to flattening the array with multiple layers
From the other solution before and the developer's network, There is an effective solution:
var arr1 = [1,2,3,[1,2,3,4, [2,3,4]]];
function flattenDeep(arr1) {
return arr1.reduce((acc, val) => Array.isArray(val) ? acc.concat(flattenDeep(val)) : acc.concat(val), []);
}
flattenDeep(arr1);// [1, 2, 3, 1, 2, 3, 4, 2, 3, 4]
However, there is a couple questions about the theory at that back that I want to ask:
1. In my understanding, the function starts with initial value acc, and then it keeps looping all the element to see if it is an array or not.
In this case, the first 3 elements are 1,2,3 -- therefore is not an array and will be accumulated and returned as an array.
But start from the fourth element it returns
Array.isArray(arr1[3])
(5) [1, 2, 3, 4, Array(3)]
In this case, it triggers the condition acc.concat(flattenDeep(val)), which is a recursion of the function. How this condition helps to flatten the array?
And for the [] at the back, if my understand is right, it indicates the return form of the result from reduce should be an array?
Last but not least, any good reference for this topics that I should look for?
May thanks for your help!
Further elaboration:
let's say, now the val in the reduce function above is [1, 2, 3, 4,[[2,3,4]]].
In this first round of checking, the elements 1,2,3,4 are not array, but the last element still does, and it makes the whole argument still an array. For the next round of the recursion, would it just take the element [[2,3,4]]] and further evaluate the elements inside this array?
Or with this example, what would be the first, second and third round outcome of the recursion process?
Second argument in the reduce method is the starting condition. If there is nothing provided, first acc will be the first array's element (see array.prototype.reduce on mdn).
I'm not sure about the But there is nth to indicate the reduction of the array statement. You're calling function recursively until you will find something that's not an array and then you're returning that value.
Look for js call stack, understand how js is stacking the functions, you can even draw it, it will help definitely because it's not easy case :)
This question already has answers here:
Deleting array elements in JavaScript - delete vs splice
(29 answers)
Closed 4 years ago.
I couldn't find a question that specifically targets the issue I'm having hence this question is being asked.
I have an array that holds 5 numbers:
var numbers = [0,1,2,3,4];
Once a number is clicked on the frontend (website), the number is removed from the array using the below code:
delete numbers[1];
This removes the correct number but leaves a space where the number was (the space is undefined). I believe this is causing an issue. After a number is removed from the array, I use another function to randomly pick any of the remaining numbers in the array however it sometimes fails. After much thought, I've realized it may be because there are empty spaces in the array after a number is removed and as a result, the code fails to work due to the undefined element.
Is my analogy correct or am I mistaken?
(I have also attempted to use the splice method to remove the number however that then causes an issue with the length of my array because if I later want to remove another number, it removes the wrong one due to the numbers moving around etc).
What you'd want to use is splice
In your specific case, numbers.splice(1,1)
You're correct that delete replaces one of the values in the array with undefined, and does not change the array length. Later on when you randomly choose an element from the array, you can wind up getting that undefined value, because it's still taking up a slot in the array:
var numbers = [0,1,2,3,4];
delete numbers[3];
console.log(numbers)
Instead use splice, which removes the item from the array completely:
var numbers = [0,1,2,3,4];
numbers.splice(3,1) /// remove one element starting at index 3
console.log(numbers)
if I later want to remove another number, it removes the wrong one due to the numbers moving around
You do need to choose one behavior or the other. If you need to preserve indexes as is, then continue to use delete, leaving the undefined values in the array, and rewrite your "choose one at random" function to never pick undefined values:
// start with some undefined values:
var numbers = [0, 1, undefined, undefined, undefined, 5]
var pickRandom = function(numbers) {
// make a copy of the array, removing undefined elements:
var definedValues = numbers.filter(function(item) {
return item !== undefined;
});
if (definedValues.length === 0) {return false}
//choose one at random:
return definedValues[Math.floor(Math.random() * definedValues.length)]
}
// test it:
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
console.log(pickRandom(numbers));
(...but note that this suggests that a simple array is the wrong data structure to use here; you may be better off with an array of objects each with an explicit ID, so you can reference specific ones as needed without worrying about keeping the array index the same.)
If you mean to actually remove the element from the array, leaving your array with 4 elements, then you can use
numbers.splice(1);
This will remove the element in the index 1 from the array and return the section of the new array.
I have one array something like following:
$scope.blinkedBoxes=[3,4,1,2,..]
It will have upto 8 elements in total (elements will be one of the numbers from 1,2,3,4).
Another array is like following:
$scope.clickedImages=[2,4,3,1,...]
I am building following function:
$scope.checkCrossCorrectness = function(array1, array2){}
My requirement is:
If the first element of $scope.blinkingBoxes is 2 (or basically any from 1, 2, 3, 4) then in $scope.clickedImages first element can not be 2 (or same as first element of first array), instead could be 1, 3, or 4.
This logic continues for further elements as well (i.e. in first array at second position if 3 comes then in second array second position can be occupied by either 1, 2 or 4)
How can I implement this?
I dont really know if this has anything to do with angular specifically, but from what I can tell a simple forEach loop will do to check equality between the indexes.
Example:
$scope.blinkedBoxes = [1, 2 ..] // etc
$scope.clickedImages = [2, 1, ..] // etc
function functionToRunOnClickOrWhatever(){
$scope.blinkedBoxes.forEach(function(val, index){
var isEqual = val === $scope.clickedImages[index];
if(isEqual){
// do something?
}
});
}