Simple CoffeeScript for loop from End to 0 - javascript

I am using CoffeeScript and I need to go through an Array from the end to the beginning in order to remove elements. It seemed like a trivial task. Here is my original code which works fine if the list length is bigger than 0 but when the list length is 0, the loop runs from -1 to 0 included.
list = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
length = list.length
for i in [length-1..0]
if list[i] >= 3 and list[i] <= 5
list.removeAt(i)
I isolated problem for a length 0 Array:
length = 0
for i in [length-1..0]
console.log '::', i
> :: -1
> :: 0
In regular JavaScript, there would be no problem:
length = 0
for (i = length - 1; i >= 0; i--){
console.log('::', i)
}
// no output
I can't find any way to code a for loop in CoffeeScript that will behave like the JavaScript loop above.
I found an alternative solution using a while loop but it's not pretty. I would like avoiding wrapping my for loop inside an if. Any way to do a CoffeeScript loop for that would behave like the simple JavaScript loop above?

Assuming your end goal is to iterate through a list in reverse order (which seems to be the case based on your original code), you can achieve this in CoffeeScript like
list = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1]
for i in list by -1
console.log i;
which compiles into
var i, j, list;
list = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1];
for (j = list.length - 1; j >= 0; j += -1) {
i = list[j];
console.log(i);
}
You can play around with it to check that it also works for empty lists.
If you need the index in the loop body as well, use
for e, i in list by -1
console.log e // array element
console.log i // array index

You said that you need to loop from the end to the beginning so your loop in js would actually be
for (i = length - 1; i >= 0; i--){
console.log('::', i)
}
In CoffeeScript, this could be implemented as follows:
i = length - 1
while i >= 0
console.log '::', i
i--

More CoffeeScript solution:
list = [10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0]
new_list = (i for i in list when i < 2 or i > 5)
or only print:
console.log i for i in list when i < 2 or i > 5

Related

How can you use .indexOf to locate the index of an array where the numbers stop increasing?

I'm taking in an array and need to return the index value where the numbers start to increase or decrease. The numbers in the array either increase then decrease [1, 3, 6, 4, 3](output = 2) decrease then increase [6, 4, 10, 12, 19](output = 1) or the same sequence [1, 3, 5, 7, 9](output = -1). For now I'm just focused on returning the index of an array that increase then decrease, then I think I can figure the other conditions out.
function ArrayChallenge(arr){
for(let i = 0; i < arr.length; i++){
if(arr[i]>arr[i+1]){
console.log(arr.indexOf(arr[i]>arr[i+1]))
}
}
}
console.log(ArrayChallenge([1, 2, 4, 5, 7, 3]))
To me the code says, take in the argument for the parameter(arr), then the for loop will go through each index and compare i with i+1, if i is greater than i+1 that means the sequence is decreasing. If that's the case I'd like to console log the index where that's actually happening. For my example code above the output should be 5 because that's the index where the numbers start decreasing, but I'm getting -1 which means the element cannot be found. If someone knows where I'm going wrong and can point me in the right direction that would be great, I'm pretty sure I'm using the .indexOf method incorrectly, but I don't know why.
"arr[i]>arr[i+1]" returns a bool "true". Your array does not contain any bool values so there is no matching index for it.
Therefore it returns -1 because it can not find any matching element.
EDIT:
If you want to print out the "moment" when your values are decreasing you can try something like this:
console.log('Decreasing from index: ' + arr.indexOf(arr[i]) + ' to ' + arr.indexOf(arr[i + 1]))
Use return arr[i] instead of console.log(arr.indexOf(arr[i]>arr[i+1]))
function ArrayChallenge(arr){
for(let i = 0; i < arr.length; i++){
if(arr[i]>arr[i+1]){
return arr[i]
}
}
}
console.log(ArrayChallenge([1, 2, 4, 5, 7, 3]))
output: 7
You can use ES6 Classes concept to achieve the requirement you have.
Working Demo :
// Defining class using es6
class arrayChallenge {
constructor(input_array) {
this.input_array = input_array;
}
getIncreaseThenDecrease() {
for(let i = 0; i < this.input_array.length; i++) {
if(this.input_array[i]>this.input_array[i+1]) {
return this.input_array.indexOf(this.input_array[i])
}
}
}
getdecreaseThenIncrease() {
for(let i = 0; i < this.input_array.length; i++) {
if(this.input_array[i] < this.input_array[i+1]) {
return this.input_array.indexOf(this.input_array[i])
}
}
}
}
// Making object with the help of the constructor
let arrayChallengeObject = new arrayChallenge([1, 2, 4, 5, 7, 3]);
console.log(arrayChallengeObject.getIncreaseThenDecrease());
console.log(arrayChallengeObject.getdecreaseThenIncrease());

Sequence in an array

I have an algo exercise to do and I have no idea how to do it, as the requirement is to use only basic programming concepts. So - the point is to find the longest sequence of numbers in an array that are growing or not changing value.
So for the array [1,1,2,4,0,1,7,4], it would be [1,1,2,4].
It should have as small time and memory complexity as possible. Any solutions, tips? Much love and thanks in advance for any advice or feedback.
That's what I've managed to do in the last 10 minutes, but I feel like I'm doing it in the most complex way possible...
function idk(array) {
var current = 0;
var winner = 0;
var currentArray = [];
var winnerArray = [];
for (let i = 0; i <= array.length; i++) {
if (array[i + 1] >= array[i]) {
currentArray.push(array[i]);
current = currentArray.length;
} else {
currentArray.push(array[i]);
if (currentArray.length > best.length) {
// copy array and append it to the new array?
}
}
}
return winnerArray;
}
Try this javascript algorithm:
var array = [1, 8, 1, 1, 5, 7, 2, 2]
var output = []
array.forEach(function(value, index) {
if (array[index - 1] <= value && index != 0) {
output[output.length - 1].push(value)
} else {
output.push([value])
}
})
var longestArray = []
output.forEach(function(arrayCompare, index) {
if (arrayCompare.length > longestArray.length || index == 0) {
longestArray = arrayCompare
}
})
console.log(longestArray)
The first forEach loops through the elements of array. If the element is larger than or equal to the previous element, it adds it to the last array in output. If it is not, then it creates a new array, and pushes the array into output. This creates arrays with "growing" sequences.
After that, it loops through each sequence, and checks if the length of the sequence is greater than the current longest sequence, which is stored in longestArray. If it is, it changes longestArray to that. If it isn't, it does nothing.
Note that both of these loops have exceptions if the index is 0, since there is no element with index -1 (therefore such an exception had to be made).
Also, here's the same implementation in python:
array = [1, 8, 1, 1, 5, 7, 2, 2]
output = []
index = 0
while index < len(array):
value = array[index]
if (array[index-1] <= value and index !=0):
output[-1].append(value)
else:
output.append([value])
index += 1
longestArray = []
index = 0
while index < len(output):
arrayCompare = output[index]
if index==0 or len(arrayCompare) > len(longestArray):
longestArray = arrayCompare
index += 1
print(longestArray)
Just why loop over the end of the array?
Because you could take this advantage to gather the last longest sequence without having a check after the loop for having found a longest sequence.
But in parts:
Why not a temporary array? Because there is no need to use it, if you collect the values. the startignn index of a sequence is important and the actual indec to decide if the sequence is longer then the previously found one.
The loop feature two conditions, one for continuing the loop, if in sequence and another to check if the actual ended sequence is longer. And for storing the actual index.
The last loop with a check for an undefined value is false, it does not continue the loop and the nect check reveals either a new longest sequence or not.
Some other annotation:
winnerArray has to be an empty array, because of the check later for length
The sequence check take the previous element, because the loop starts with the first index and the previous element is given.
The Big O is O(n).
function idk(array) {
let winnerArray = [],
index = 0;
for (let i = 1; i < array.length + 1; i++) {
if (array[i - 1] <= array[i]) continue;
if (i - index > winnerArray.length) winnerArray = array.slice(index, i);
index = i;
}
return winnerArray;
}
console.log(...idk([1, 1, 2, 4, 0, 1, 7, 4])); // [1, 1, 2, 4]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2])); // [1, 1, 5, 7]
console.log(...idk([1, 8, 1, 1, 5, 7, 2, 2, 2, 2, 2]));
Here is the dynamic programming algorithm in Python:
def longest_sequence(numbers):
length = len(numbers)
L = [0] * length #L stores max possible lengths at each index
L[-1] = 1 # base case
for i in range(length-2, -1, -1):
max_length = L[i]
for j in range(i, length):
if (L[j] > max_length) and (numbers[j] > numbers[i]):
max_length = L[j]
L[i] = max_length + 1
#trace back
max_length = max(L)
result = []
for k in range(max_length, 0, -1):
result.append(numbers[L.index(k)])
numbers = numbers[L.index(k):]
L = L[L.index(k):]
return result
my_numbers = [36,13,78,85,16,52,58,61,63,83,46,19,85,1,58,71,26,26,21,31]
print(longest_sequence(my_numbers))
#>>[13, 16, 52, 58, 61, 63, 83, 85]
To be optimal, you should not use intermediate lists during processing. You only need to hold indexes, sizes and the previous value:
def longSeq(A):
longStart,longSize = 0,0 # best range so far (index and size only)
start,size,prev = 0,0,None # current range (index and size)
for i,a in enumerate(A):
if i == 0 or prev <= a: # increase current range
size += 1
prev = a
if size > longSize: # track longest so far
longStart,longSize = start,size
else:
start,size,prev = i,1,a # sequence break, restart current
return A[longStart:longStart+longSize]
output:
print(longSeq([1,1,2,4,0,1,7,4])) # [1, 1, 2, 4]
print(longSeq( [1,8,1,1,5,7,2,2])) # [1, 1, 5, 7]
This will perform in O(n) time and use O(1) space.

Issue trying to find length of sequence in an array

I'm trying to find the length of the sequence in an array, between the first and the second occurance of a specified number.
For Example: lengthOfSequence([0, -3, 7, 4, 0, 3, 7, 9], 7) would return 5, because there are 5 indices between the first and second occurrence of the number 7.
I feel like the code that I have written should work, but after console logging it looks as if my arr.push() method is only pushing the first index to my indexes array variable, and its pushing it twice. Why would this be happening?
Here is my code for context:
var lengthOfSequence = function (arr, n) {
var indexes = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] === n) {
indexes.push(arr.indexOf(arr[i]));
}
}
return arr.indexOf(indexes[1]) - arr.indexOf(indexes[0]);
}
So, for example, if I use my array that I used earlier lengthOfSequence([0, -3, 7, 4, 0, 3, 7, 9], 7), my for loop would find the first occurrence of 7 (index 2) and push it to my index array variable, but it would just do it twice. So my indexes array would just be [2,2]. Why would it not be [2,6]?
indexOf does not do what you think it does. It returns the index of the first item that it finds with the provided value. For both values in the array, it returns that first index.
Since you want the index only and you are already iterating over it with your loop, you can simply use i itself:
indexes.push(i);
You may do it as follows but don't know why it is 5 that you want. I guess it should be 4. OK lets make it 5.
function lengthOfSequence(a,f){
var fi = a.indexOf(f);
return a.slice(fi)
.indexOf(f)+(2*fi+1);
}
var a = [0, -3, 7, 4, 0, 3, 7, 9],
f = 7;
console.log(lengthOfSequence(a,f));
You could use just the index and return the difference between the last element of indices and the first one plus one.
var lengthOfSequence = function(arr, n) {
var indexes = [];
for (var i = 0; i < arr.length; i++) {
if (arr[i] === n) {
indexes.push(i);
}
}
return indexes[indexes.length - 1] - indexes[0] + 1;
}
console.log(lengthOfSequence([0, -3, 7, 4, 0, 3, 7, 9], 7)); // 5
console.log(lengthOfSequence([0, -3, 7, 4, 0, 3, 7, 9], -3)); // 1

Can anyone tell me why this loop isn't working as it should?

This is for an exercise on codewars.com. The idea is to make a function that takes an array as the first parameter, then deletes each item in sequence defined by the second parameter, so if the second parameter is 3, it'll delete 3 first(counting for this one is supposed to be 1 based, not 0 based), then 6, then 9, then back around to 2, as though all the items were in a circle, then 7 (because 3 and 6 are gone), etc, then return the items in the order in which they were deleted (this pattern is referred to as a Josephus permutation).
So here's my code:
function josephus(items, k) {
var arr = [];
var l = items.length;
var a = k - 1;
for (var i = 0; i < l; i++) {
arr.push(items[a]);
items.splice(a, 1);
a += k - 1 ;
if (a >= items.length) { a = a - items.length; }
}
return arr;
}
It works sometimes. It worked right with josephus([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 1), but then with josephus([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], 2), it worked until the last number(5, in this case), then returned null. In fact, most times, it returns null in the place of the last item. Can anyone tell me why it's doing this? If you have a codewars account, you can try it out in its context here: http://www.codewars.com/kata/5550d638a99ddb113e0000a2/train/javascript
Your index re-calculation isn't working. i.e. a = 3, items = [1] a becomes 2, items[2] is undefined. Try this code:
function j(items,k){
var arr = [];
var l = items.length;
var a = k - 1;
for(var i = 0; i<l; i++){
arr.push(items[a]);
items.splice(a, 1);
a += k - 1 ;
a = a % items.length;
}
return arr;
}
Replace
arr.push(items[a]);
with
arr.push(items[a%items.length]);

Select X amount forward and backwards in an array, looping to beginning and end if needed

I need to, given an array index and a range, loop forwards X amount and backwards X amount in the array returning the new indexes.
If the loop reaches the end of the array going forwards, it continues at the beginning of the array. If the loop reaches the beginning while going backwards, it continues at the end of the array.
for example, with the array:
[0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
Given an index of 8, and a range of 3, the function would return [5, 6, 7 ,8, 9, 0, 1]
Or, given an index of 1, and a range of 3, it would return [8, 9, 0, 1, 2, 3, 4]
I tried writing a solution but it only worked for a fixed range number and was incredibly crude. Just wondering if there is a succinct way to achieve this. Javascript solution preferred, but I'm happy to translate the logic from another language if needed.
Thank you.
using modulus this is pretty easy:
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
index = 8,
n = 3;
var result = [];
for (var i = index - n, len = array.length; i <= index + n; i++) {
result.push(array[(i + len) % len]);
}
console.log(result);
Edit JSFiddle: http://jsfiddle.net/cmymS/
An explanation for the modulo operator in this example:
The modulo operator handles going over the boundaries. Inside of the for loop, i is a 'virtual' index in the array that can be less than 0 or >= len. You can think of this as having infinite repetitions of your array both on the left and right of your actual array. If i < 0, we are accessing one of the virtual arrays to the left, if i >= len, we're accessing one of the virtual arrays to the right. The index transformation (i + len) % len then handles translating 'virtual' indices back into actual array indices.
There are two boundary conditions and the case of accessing a 'normal' index:
a) i < 0: Consider e.g. i = -3.
(i + len) will shift the position by one whole array so that we're working in the virtual array to the right, but pointing at the same element. The modulus has no effect since len - 3 is smaller than len.
b) i >= len: Consider e.g. i = len + 4
(i + len) will shift the position one array to the right. In our example, (i + len) will be (len + 4 + len) but the modulo neutralizes those shifts so we get 4.
c) i is a valid index in the original array
(i + len) will shift the position one array to the right, but this is reset by the modulus since 0 <= i < len. (i + len) % len = i.
function carousel(array, index, n) {
var result = [];
for (var i = index - n, len = array.length; i <= index + n; i++) {
result.push(array[i < 0 ? len + i : i > len - 1 ? i - len : i]);
}
return result;
}
// TEST
var array = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9],
index = 8,
n = 3;
console.log(carousel(array, index, n));
DEMO: http://jsfiddle.net/SUGhf/
I was looking for something that will give me same thing but not only using index from array but arbitrary position that can go infinity (ie +100 - 100) so i just added one line to code above in this case -12. If someone needed it.
function carousel(array, arbitraryIndex, n) {
var result = [];
index = arbitraryIndex % (array.length);
for (var i = index - n, len = array.length; i <= index + n; i++) {
result.push(array[i < 0 ? len + i : i > len - 1 ? i - len : i]);
}
return result;
}
var array = [0, 1, 2, 3, 4, 5],
arbitraryIndex = -12,
n = 3;
console.log(carousel(array, arbitraryIndex, n));

Categories

Resources