Related
I'm learning for loops in JS and am trying to learn how to console.log the first and last element in an array on one iteration, then console.log the second and second to last elements, etc.
here's what I have tried:
for (let i=0; i<myArray.length; i++){
console.log(myArray[i]);
console.log(myArray[i-1];
}
This is printing elements from my array, but not in the correct order
So what you are trying to achieve is to print the last element, the second last element, etc...
You can use the myArray.length property to do it, just substract the iterator + 1 to the array length and obtain the result you want.
for (let i=0; i<myArray.length; i++){
console.log(myArray[i]);
console.log(myArray[myArray.length - (i + 1)]);
}
The (i + 1) is because the .length property returns the number of item of the array, but not the maximum index of the array. So if the length of the array is 5, the maximum index of the array is 4 (since index starts from 0). You can also write it like: myArray[myArray.length - i - 1]
Here an example:
const myArray = [1, 2, 3, 4, 5];
for (let i=0; i<myArray.length; i++){
console.log(myArray[i]);
console.log(myArray[myArray.length - (i + 1)]);
}
Create a temporary copy of your array, then use shift (to remove the head element) and pop (to remove the tail element) until the copy is empty:
const realArray = [1, 2, 3, 4, 5, 6, 7, 8, 9];
const temporary = realArray.slice();
while (temporary.length) {
const e1 = temporary.shift();
// do something with e1
console.log(e1);
const e2 = temporary.pop();
if (e2) {
// note that e2 _might not exist_ so: always test
console.log(e2);
}
}
You can use two counters that works on opposite direction
i will move forward with increment as i++.
j will move backward with decrement as j--.
If there are even numbers of elements in an array then you should print both numbers arr[i] and arr[j]. But be sure to handle the odd number of elemetns in an array then you have to print either of arr[i] or arr[j]
function print(arr) {
let i = 0;
j = arr.length - 1;
while (i <= j) {
if (i !== j) {
console.log(arr[i], arr[j]);
} else console.log(arr[j]);
i++;
j--;
}
}
print([1, 2, 3, 4, 5, 6, 7, 8]);
print([1, 2, 3, 4, 5, 6, 7, 8, 9]);
Here's one way to do it, reverse the array and use the same index. Since array.reverse() mutates the original array, we slice() it in order to use a copy.
let array = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10];
array.forEach((a, i) => {
let b = array.slice().reverse()[i]
if (i < array.length / 2) console.log(a, b)
})
let output = '';
for (let i = 0; i < (myArr.length) /2; i++){
output += myArr[i] + myArr[myArr.length-1-i];
}
console.log(output)
Just check for i === 0 to indicate the start of the loop and hence, you can print the last element of array
const myArray = ['first', 1, 2, 3, 'last'];
for (let i = 0; i < myArray.length - 1; i++) {
console.log(myArray[i]);
if (i === 0) {
console.log(myArray[myArray.length - 1]);
}
}
LeetCode's Max Chunks To Make Sorted II challenge is:
Given an array arr of integers (not necessarily distinct), we split
the array into some number of "chunks" (partitions), and individually
sort each chunk. After concatenating them, the result equals the
sorted array.
What is the most number of chunks we could have made?
Example:
Input: arr = [2, 1, 3, 4, 4]
Output: 4
Explanation:
We can split into two chunks, such as [2, 1], [3, 4, 4].
However, splitting into [2, 1], [3], [4], [4] is the highest number of chunks possible.
The algorithm underlying the following solution is (the algorithm and the solution were posted as a comment on the solution page by a user named #benevolent. Unfortunately, I can't link to its comment):
If the largest number from arr[0] to (including) arr[k] is less than or equal to the smallest
number from arr[k+1] to the end, then we can split into two valid
chunks.
To illustrate:
left right
[......max] [min......]
To know the minimum element from k to arr.length-1, we can just
precompute from right to left.
The solution:
function maxChunksToSorted(arr) {
var minRight = Array(arr.length).fill(Number.MAX_SAFE_INTEGER);
for (var i = arr.length-2; i >= 0; --i) {
minRight[i] = Math.min(minRight[i+1], arr[i+1]);
}
var maxLeft = Number.MIN_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
maxLeft = Math.max(maxLeft, arr[i]);
if (maxLeft <= minRight[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
My question:
I was trying to make a "mirror image" of the above solution, by "flipping" every action (e.g, the use of min becomes max, <= becomes >, and so on).
My maxArr indeed mirrors minRight (e.g., for [2, 1, 3, 4, 4], my maxArr is [MIN_SAFE_INTEGER, 1, 3, 4, 4], while the original minRight is [1, 3, 4, 4, MAX_SAFE_INTEGER]), but it clearly doesn't work, and I can't put my finger on the reason for that.
What's my fundamental problem?
Let me stress that I'm not looking for some other working solution. I'd like to understand what went wrong with my mirror solution, if it's even possible to make this mirror, and if not - what's the fundamental reason for that.
function maxChunksToSorted(arr) {
var maxArr = Array(arr.length).fill(Number.MIN_SAFE_INTEGER);
for (var i = 1; i <= arr.length; ++i) {
maxArr[i] = Math.max(maxArr[i-1], arr[i]);
}
var minLeft = Number.MAX_SAFE_INTEGER;
var ans = 0;
for (var i = 0; i < arr.length; ++i) {
minLeft = Math.min(minLeft, arr[i]);
if (minLeft > maxArr[i]) {
ans += 1
}
}
return ans;
};
console.log("expects: 1", "got:", maxChunksToSorted([5, 4, 3, 2, 1]));
console.log("expects: 4", "got:", maxChunksToSorted([2, 1, 3, 4, 4]));
This should do the job:
function chunk(list){
let sortedList = list.slice();
sortedList.sort();
var beginIndex = -1; var biggestFound;
var foundFirst = false; var foundLast = false;
for(var i = 0; i < list.length; i++){
if(beginIndex == -1) {
if(list[i] == sortedList[i]) print(list[i]);
else {beginIndex = i; biggestFound = list[i];}
}
else{
if(list[i] == sortedList[beginIndex]) foundFirst = true;
if(list[i] > biggestFound) biggestFound = list[i];
if(biggestFound == sortedList[i]) foundLast = true;
if(foundFirst && foundLast){
print(list.slice(beginIndex, i - beginIndex + 1));
foundFirst = false; foundLast = false; beginIndex = -1;
}
}
}
}
chunk([2,1,3,4,4]);
As I commented, if a chunk starts at position i, it must contain the element that corresponds to the position i in the sorted array and if it ends in position j, it must contain the element in the index j of the sorted array.
When both of these conditions are satisfied, you close the chunk and start a new one.
The complexity is O(n lg(n)), where n is the size of the array.
I'm trying to write a function that will identify the longest period of variance in an array of numbers. Variance begins when the previous number is higher than the current, and ends when the next number is the same as the current; however, if variance doesn't end, then it is assumed the variance began with the last two numbers.
For example: [10, 5, 3, 11, 8, 9, 9, 2, 10] The longest period of variance in this array is [5, 3, 11, 8, 9], or just 5 (the length). A variance ends when the following number is the same as the current, in this case, 9.
The function I've written works on this case; however, it doesn't when the entire array has variance, such as [10, 5, 10, 5, 10, 5, 10, 5, 10], which returns 8, when it should be 9.
In the case where the previous number is number is always lower, or always higher than the variance would be 2, because it never ended. For example [2, 4, 6, 8] and [8, 6, 4, 2].
I know the issue with the entire array variance can be solved by starting the for loop at 0, but then the other cases become invalid. Any help is greatly appreciated.
Without further ado, here is my code:
function findVariance(numbers) {
if ([0,1].includes(numbers.length)) return numbers.length;
const variance = [[0]];
let greater = numbers[1] > numbers[0];
let lesser = numbers[1] < numbers[0];
for (let i = 1; i < numbers.length; i++) {
let previous = variance.length - 1;
let previousVarianceGroup = variance[previous];
let previousVarianceGroupValue = previousVarianceGroup[previousVarianceGroup.length - 1];
if (greater) {
if (numbers[i] < numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = false;
lesser = true;
} else {
greater = numbers[i] < numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else if (lesser) {
if (numbers[i] > numbers[previousVarianceGroupValue]) {
previousVarianceGroup.push(i);
greater = true;
lesser = false;
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] > numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
} else {
greater = numbers[i] > numbers[previousVarianceGroupValue];
lesser = numbers[i] < numbers[previousVarianceGroupValue];
variance.push([previousVarianceGroupValue, i]);
}
}
const result = [];
for (let i = 0; i < variance.length; i++) {
result[i] = variance[i].length;
}
result.sort();
return result[result.length - 1];
}
console.log(findVariance([10, 5, 3, 11, 8, 9, 9, 2, 10]));
console.log(findVariance([10, 5, 10, 5, 10, 5, 10, 5, 10]));
console.log(findVariance([2, 4, 6, 8]));
Here's what I got (trying to understand the question as best i could)
function calculateVariance(arr) {
// trivial cases
if (arr.length <= 1) { return arr.length; }
// store the difference between each pair of adjacent numbers
let diffs = [];
for (let i = 1; i < arr.length; i++) {
diffs.push(arr[i] - arr[i - 1]);
}
let max = 0;
// if the difference between two numbers is 0, they're the same.
// the base max variance encountered is 1, otherwise it's 2.
// the boolean zen here is that diffs[0] is falsy when it's 0, and truthy otherwise
let count = diffs[0] ? 2 : 1;
// go through the array of differences,
// and count how many in a row are alternating above/below zero.
for (i = 1; i < diffs.length; i++) {
if ((diffs[i] < 0 !== diffs[i - 1] < 0) && diffs[i] && diffs[i - 1]) {
count++;
} else {
max = Math.max(count, max);
// see above
count = diffs[i] ? 2 : 1;
}
}
// account for the maximum variance happening at the end
return Math.max(count, max);
}
You are overcomplicating things a bit, just increase a counter as long as an element equals the next one, reset on equal:
const counts = [];
let count = 0;
for(let i = 0; i < numbers.length - 1; i++) {
if(numbers[i] === numbers[i + 1]) {
counts.push(count);
count = 0;
} else {
count++;
}
}
counts.push(count);
return counts.sort()[counts.length - 1];
I need to find first two numbers and show index like:
var arrWithNumbers = [2,5,5,2,3,5,1,2,4];
so the first repeated number is 2 so the variable firstIndex should have value 0. I must use for loop.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var firstIndex
for (i = numbers[0]; i <= numbers.length; i++) {
firstIndex = numbers[0]
if (numbers[i] == firstIndex) {
console.log(firstIndex);
break;
}
}
You can use Array#indexOf method with the fromIndex argument.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
// iterate upto the element just before the last
for (var i = 0; i < numbers.length - 1; i++) {
// check the index of next element
if (numbers.indexOf(numbers[i], i + 1) > -1) {
// if element present log data and break the loop
console.log("index:", i, "value: ", numbers[i]);
break;
}
}
UPDATE : Use an object to refer the index of element would make it far better.
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
ref = {};
// iterate over the array
for (var i = 0; i < numbers.length; i++) {
// check value already defined or not
if (numbers[i] in ref) {
// if defined then log data and brek loop
console.log("index:", ref[numbers[i]], "value: ", numbers[i]);
break;
}
// define the reference of the index
ref[numbers[i]] = i;
}
Many good answers.. One might also do this job quite functionally and efficiently as follows;
var arr = [2,5,5,2,3,5,1,2,4],
frei = arr.findIndex((e,i,a) => a.slice(i+1).some(n => e === n)); // first repeating element index
console.log(frei)
If might turn out to be efficient since both .findIndex() and .some() functions will terminate as soon as the conditions are met.
You could use two for loops an check every value against each value. If a duplicate value is found, the iteration stops.
This proposal uses a labeled statement for breaking the outer loop.
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11],
i, j;
outer: for (i = 0; i < numbers.length - 1; i++) {
for (j = i + 1; j < numbers.length; j++) {
if (numbers[i] === numbers[j]) {
console.log('found', numbers[i], 'at index', i, 'and', j);
break outer;
}
}
}
Move through each item and find if same item is found on different index, if so, it's duplicate and just save it to duplicate variable and break cycle
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var duplicate = null;
for (var i = 0; i < numbers.length; i++) {
if (numbers.indexOf(numbers[i]) !== i) {
duplicate = numbers[i];
break; // stop cycle
}
}
console.log(duplicate);
var numbers = [7, 5, 7, 6, 6, 4, 9, 10, 2, 11];
var map = {};
for (var i = 0; i < numbers.length; i++) {
if (map[numbers[i]] !== undefined) {
console.log(map[numbers[i]]);
break;
} else {
map[numbers[i]] = i;
}
}
Okay so let's break this down. What we're doing here is creating a map of numbers to the index at which they first occur. So as we loop through the array of numbers, we check to see if it's in our map of numbers. If it is we've found it and return the value at that key in our map. Otherwise we add the number as a key in our map which points to the index at which it first occurred. The reason we use a map is that it is really fast O(1) so our overall runtime is O(n), which is the fastest you can do this on an unsorted array.
As an alternative, you can use indexOf and lastIndexOf and if values are different, there are multiple repetition and you can break the loop;
function getFirstDuplicate(arr) {
for (var i = 0; i < arr.length; i++) {
if (arr.indexOf(arr[i]) !== arr.lastIndexOf(arr[i]))
return arr[i];
}
}
var arrWithNumbers = [2, 5, 5, 2, 3, 5, 1, 2, 4];
console.log(getFirstDuplicate(arrWithNumbers))
var numbers = [1, 3, 6, 7, 5, 7, 6, 6, 4, 9, 10, 2, 11]
console.log(getFirstDuplicate(numbers))
I have the same task and came up with this, pretty basic solution:
var arr = [7,4,2,4,5,1,6,8,9,4];
var firstIndex = 0;
for(var i = 0; i < arr.length; i++){
for( var j = i+1; j < arr.length; j++){
if(arr[i] == arr[j]){
firstIndex = arr[i];
break;
}
}
}
console.log(firstIndex);
First for loop takes the first element from array (number 7), then the other for loop checks all other elements against it, and so on.
Important here is to define j in second loop as i+1, if not, any element would find it's equal number at the same index and firstIndex would get the value of the last one after all loops are done.
To reduce the time complexity in the aforementioned answers you can go with this solution:
function getFirstRecurringNumber(arrayOfNumbers) {
const hashMap = new Map();
for (let number of arrayOfNumbers) { // Time complexity: O(n)
const numberDuplicatesCount = hashMap.get(number);
if (numberDuplicatesCount) {
hashMap.set(number, numberDuplicatesCount + 1);
continue;
}
hashMap.set(number, 1); // Space complexity: O(n)
}
for (let entry of hashMap.entries()) { // Time complexity: O(i)
if (entry[1] > 1) {
return entry[0];
}
}
}
// Time complexity: O(n + i) instead of O(n^2)
// Space complexity: O(n)
Using the code below, I am able to get just the first '5' that appears in the array. the .some() method stops looping through once it finds a match.
let james = [5, 1, 5, 8, 2, 7, 5, 8, 3, 5];
let onlyOneFives = [];
james.some(item => {
//checking for a condition.
if(james.indexOf(item) === 0) {
//if the condition is met, then it pushes the item to a new array and then
//returns true which stop the loop
onlyOneFives.push(item);
return james.indexOf(item) === 0;
}
})
console.log(onlyOneFives)
Create a function that takes an array with numbers, inside it do the following:
First, instantiate an empty object.
Secondly, make a for loop that iterates trough every element of the array and for each one, add them to the empty object and check if the length of the object has changed, if not, well that means that you added a element that already existed so you can return it:
//Return first recurring number of given array, if there isn't return undefined.
const firstRecurringNumberOf = array =>{
objectOfArray = {};
for (let dynamicIndex = 0; dynamicIndex < array.length; dynamicIndex ++) {
const elementsBeforeAdding = (Object.keys(objectOfArray)).length;0
objectOfArray[array[dynamicIndex]] = array[dynamicIndex]
const elementsAfterAdding = (Object.keys(objectOfArray)).length;
if(elementsBeforeAdding == elementsAfterAdding){ //it means that the element already existed in the object, so it didnt was added & length doesnt change.
return array[dynamicIndex];
}
}
return undefined;
}
console.log(firstRecurringNumberOf([1,2,3,4])); //returns undefined
console.log(firstRecurringNumberOf([1,4,3,4,2,3])); //returns 4
const arr = [1,9,5,2,3,0,0];
const copiedArray = [...arr];
const index = arr.findIndex((element,i) => {
copiedArray.splice(0,1);
return copiedArray.includes(element)
})
console.log(index);
var addIndex = [7, 5, 2, 3, 4, 5, 7,6, 2];
var firstmatch = [];
for (var i = 0; i < addIndex.length; i++) {
if ($.inArray(addIndex[i], firstmatch) > -1) {
return false;
}
firstmatch.push(addIndex[i]);
}
If I have an array of [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7] and wanted to find each case of 3 consecutive numbers (whether ascending or descending), how would I do that?
Second part would be then to alert an array with the index of each of these sequences.
For ex. the previous array would return [0,4,6,7].
So far I have this... which is a rough start
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 1; i < arr.length; i++) {
if ((arr[i] - arr[i-1] != 1) && (arr[i] - arr[i+1] != 1)) {
results.push(arr[i]);
}
}
alert(results);
Thanks for the help!
Thanks for the math.abs pointer. This is what I ended up doing:
var array = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var indexes = [];
for(var i=0; i < array.length; i++) {
var diff = array[i+1] - array[i];
if(Math.abs(diff)==1 && array[i+1]+diff == array[i+2]) {
indexes.push(i);
}
}
alert(indexes);
It'd be interesting to know the context of this task as well... Anyway, here's my solution:
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
var limit = arr.length - 1;
var sequence = 0;
for (var i = 0; i < limit; ++i) {
var diff = arr[i+1] - arr[i];
if (sequence && sequence === diff) {
results.push(i-1);
continue;
}
sequence = (diff === 1 || diff === -1) // or ... Math.abs(diff) === 1
? diff
: 0;
}
console.log(results);
The idea is simple: we don't need to compare two neighbors twice. ) It's enough to raise a kind of sequence flag if this comparation starts a sequence, and lower it if no sequence is there.
This is a very literal approach to your question - I have only checked forwards numbers, but adding reverse would be done almost in the same way
var arr = [1, 2, 3, 4, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 0; i < arr.length; i++) {
// if next element is one more, and one after is two more
if (arr[i+1] == arr[i]+1 && arr[i+2] == arr[i]+2){
// store the index of matches
results.push(i);
// loop through next numbers, to prevent repeating longer sequences
while(arr[i]+1 == arr[i+1])
i++;
}
}
console.log(results);
You need to look closely at your expression in your if statement.
It currently says:
If the difference between the current element and previous element is not 1, and
If the difference between the current element and next element is not 1
then it's a result.
So, on the face of it, that's an incorrect logical statement to determine if the current element is in the middle of a consecutive set of three.
In addition, this doesn't account for an ascending or descending set of three either.
Try figuring out, in words, what the condition would look like and go from there.
Some things to consider
I suggest you start going through the list from i = 2
Research Math.abs
This is I think a simpler way to do it. First check the average of the left and right number is equal to the middle, then check that the absolute value of either neighbor is one.
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var indexes = [];
for(var i=1; i < arr.length; i++) {
if((arr[i-1]+arr[i+1]) / 2 == arr[i] && Math.abs(arr[i]-arr[i-1]) == 1) {
indexes.push(i-1);
}
}
alert(indexes);
var arr = [1, 2, 3, 5, 10, 9, 8, 9, 10, 11, 7];
var results = [];
for (var i = 0; i < arr.length - 2; i++) {
if ((arr[i+1] - arr[i] === 1) && (arr[i+2] - arr[i+1] === 1)) {
results.push({
i:i,
mode:'up',
arr:[arr[i],arr[i+1],arr[i+2]
});
}
if ((arr[i+1] - arr[i] === -1) && (arr[i+2] - arr[i+1] === -1)) {
results.push({
i:i,
mode:'down',
arr:[arr[i],arr[i+1],arr[i+2]
});
}
}
alert(results);