Ruby didn't loop all elements? - ruby

I am trying to remove all 7s from an array:
a = [1,2,3,4,5,7,7,7,7,7,7,7,7,7,9,10,11,12,13]
I did:
a.each_with_index do |item, index|
if item == 7
a.delete_at(index)
end
end
a # => [1, 2, 3, 4, 5, 7, 7, 7, 7, 9, 10, 11, 12, 13]
How did this happen?

The fact that only about half (5/9) of your items have disappeared is a dead giveaway that the problem is deleting while iterating over the collection.
The iteration will be processing indexes 1, 2, 3, 4 and so on. If you delete index 2 while processing it, that will shift all later indexes down by one.
So, when you then move on to index 3 in the next iteration, you will skip the original index 3 because that will have been shifted down to index 2.
In other words, let's start with a simpler example with two consecutive items to remove:
index | 0 | 1 | 2 | 3 |
value | 1 | 7 | 7 | 9 |
You check the first index and the value is 1 so you do nothing. You then check the second index and the value is 7 so you delete it, giving:
index | 0 | 1 | 2 |
value | 1 | 7 | 9 |
You then check the third index and the value is 9 so you do nothing. You've also reached the end so it stops.
So you can see there that you actually skipped the second item you wanted to delete, because you shifted things around while iterating. This isn't a Ruby-specific problem, a great many languages have this same issue.
In general, each complete pair of adjacent items will only have the first of the pair deleted while an item on its own (not followed by another of the same value) will be deleted normally. That's why only 5/9 of your 7s are deleted, one for each of the four pairs and the final standalone one.
The correct way (in Ruby) to delete all items of a single given value is to use the array delete method:
a.delete(7)
You can also use conditional delete for more complex conditions such as deleting everything greater than 7:
a.delete_if {|val| val > 7}
And, if you really want to do it yourself (as an educational exercise), you just have to realise that the problem is because you process the array in a forward manner - when you do that, changes beyond where you're deleting may cause issues.
If you were to find some way to process the array in a backwards manner, this issue would not occur. Luckily, Ruby has such a beast:
a.to_enum.with_index.reverse_each do |item, index|
That line will process the array in such a way that deletions will not affect future operations. Just be aware that deleting while iterating can still be a problem if the data structure you're processing is not a simple indexed array.
I still warrant that delete and delete_if are the correct way to go since they're baked into Ruby already, and therefore incredibly unlikely to have bugs.

This happens because in each iteration you are updating/deleting the same array which you are looping through.
For this purpose, you should use this delete method:
a = [1,2,3,4,5,7,7,7,7,7,7,7,7,7,9,10,11,12,13]
a.delete(7)
# [1, 2, 3, 4, 5, 9, 10, 11, 12, 13]
You can see the problem by running this program:
a = [1,2,3,4,5,6]
a.each_with_index do |item, index|
puts "#{index} : #{item}"
if item == 4
a.delete_at(index)
end
end
Output:
0 : 1
1 : 2
2 : 3
3 : 4 # made delete here
4 : 6 # See the problem !
Hope it helps :)

In general, deleting from the Array you're iterating over, in any language, is going to get weird. To see why, look at the code for Array#each_index.
VALUE rb_ary_each_index(VALUE ary)
{
long i;
RETURN_SIZED_ENUMERATOR(ary, 0, 0, ary_enum_length);
for (i=0; i<RARRAY_LEN(ary); i++) {
rb_yield(LONG2NUM(i));
}
return ary;
}
Note that it's really a for loop from 0 to the length of the array. The loop will just count from 0 to the original length of the array.
When you delete an item from the array, everything after it shifts over 1. If i = 5 and you call a.delete_at(i) that means a[6] is now a[5]. a[7] is now a[6]. And so on. Next iteration will have i = 6 which means you effectively skipped an element.
To illustrate, and assuming you want to delete 2.
i = 0
a = [1,2,2,2,3,4,5]
^
-------------------
i = 1
a = [1,2,2,2,3,4,5]
^
a.delete_at(i)
a = [1,2,2,3,4,5]
-------------------
i = 2
a = [1,2,2,3,4,5]
^
a.delete_at(i)
a = [1,2,3,4,5]
-------------------
i = 3
a = [1,2,3,4,5]
^
-------------------
i = 4
a = [1,2,3,4,5]
^
-------------------
i = 5
a = [1,2,3,4,5]
-------------------
i = 6
a = [1,2,3,4,5]
Note that the last two iterations have walked off the array, because the array is now two elements smaller than it was before.

Related

Convert the permutation sequence A to B by selecting a set in A then reversing that set and inserting that set at the beginning of A

Given the sequence A and B consisting of N numbers that are permutations of 1,2,3,...,N. At each step, you choose a set S in sequence A in order from left to right (the numbers selected will be removed from A), then reverse S and add all elements in S to the beginning of the sequence A. Find a way to transform A into B in log2(n) steps.
Input: N <= 10^4 (number of elements of sequence A, B) and 2 permutations sequence A, B.
Output: K (Number of steps to convert A to B). The next K lines are the set of numbers S selected at each step.
Example:
Input:
5 // N
5 4 3 2 1 // A sequence
2 5 1 3 4 // B sequence
Output:
2
4 3 1
5 2
Step 0: S = {}, A = {5, 4, 3, 2, 1}
Step 1: S = {4, 3, 1}, A = {5, 2}. Then reverse S => S = {1, 3, 4}. Insert S to beginning of A => A = {1, 3, 4, 5, 2}
Step 2: S = {5, 2}, A = {1, 3, 4}. Then reverse S => S = {2, 5}. Insert S to beginning of A => A = {2, 5, 1, 3, 4}
My solution is to use backtracking to consider all possible choices of S in log2(n) steps. However, N is too large so is there a better approach? Thank you.
For each operation of combined selecting/removing/prepending, you're effectively sorting the elements relative to a "pivot", and preserving order. With this in mind, you can repeatedly "sort" the items in backwards order (by that I mean, you sort on the most significant bit last), to achieve a true sort.
For an explicit example, lets take an example sequence 7 3 1 8. Rewrite the terms with their respective positions in the final sorted list (which would be 1 3 7 8), to get 2 1 0 3.
7 -> 2 // 7 is at index 2 in the sorted array
3 -> 1 // 3 is at index 0 in the sorted array
1 -> 0 // so on
8 -> 3
This new array is equivalent to the original- we are just using indices to refer to the values indirectly (if you squint hard enough, we're kinda rewriting the unsorted list as pointers to the sorted list, rather than values).
Now, lets write these new values in binary:
2 10
1 01
0 00
3 11
If we were to sort this list, we'd first sort by the MSB (most significant bit) and then tiebreak only where necessary on the subsequent bit(s) until we're at the LSB (least significant bit). Equivalently, we can sort by the LSB first, and then sort all values on the next most significant bit, and continuing in this fashion until we're at the MSB. This will work, and correctly sort the list, as long as the sort is stable, that is- it doesn't change the order of elements that are considered equal.
Let's work this out by example: if we sorted these by the LSB, we'd get
2 10
0 00
1 01
3 11
-and then following that up with a sort on the MSB (but no tie-breaking logic this time), we'd get:
0 00
1 01
2 10
3 11
-which is the correct, sorted result.
Remember the "pivot" sorting note at the beginning? This is where we use that insight. We're going to take this transformed list 2 1 0 3, and sort it bit by bit, from the LSB to the MSB, with no tie-breaking. And to do so, we're going to pivot on the criteria <= 0.
This is effectively what we just did in our last example, so in the name of space I won't write it out again, but have a look again at what we did in each step. We took the elements with the bits we were checking that were equal to 0, and moved them to the beginning. First, we moved 2 (10) and 0 (00) to the beginning, and then the next iteration we moved 0 (00) and 1 (01) to the beginning. This is exactly what operation your challenge permits you to do.
Additionally, because our numbers are reduced to their indices, the max value is len(array)-1, and the number of bits is log2() of that, so overall we'll only need to do log2(n) steps, just as your problem statement asks.
Now, what does this look like in actual code?
from itertools import product
from math import log2, ceil
nums = [5, 9, 1, 3, 2, 7]
size = ceil(log2(len(nums)-1))
bit_table = list(product([0, 1], repeat=size))
idx_table = {x: i for i, x in enumerate(sorted(nums))}
for bit_idx in range(size)[::-1]:
subset_vals = [x for x in nums if bit_table[idx_table[x]][bit_idx] == 0]
nums.sort(key=lambda x: bit_table[idx_table[x]][bit_idx])
print(" ".join(map(str, subset_vals)))
You can of course use bitwise operators to accomplish the bit magic ((thing << bit_idx) & 1) if you want, and you could del slices of the list + prepend instead of .sort()ing, this is just a proof-of-concept to show that it actually works. The actual output being:
1 3 7
1 7 9 2
1 2 3 5

How to make a for loop stop after a set number of iterations in Julia

I am still pretty new at programming and I would appreciate any help on how to approach the following problem:
Given a matrix (3x5)
a = [1 2 3 4 5;
6 7 8 9 10;
11 12 13 14 15;]
I want to iterate through every row
For each row, I want each element to be checked
With each element, I want to store a separate array that holds the element and the next 2 elements.
Ex:
Row 1 = [1 2 3 4 5]
For element 1
return newArray = [1 2 3]
For element 2
return newArray = [2 3 4]
Getting stuck on part 3. How to make the for loop check only up to the next 2 elements and then continue to the next element in the row.
I took a shot at solving what you asked for, but I agree with the others that you need to think more about what you are trying to do and what you want your output to look like. Your request does not sound like something a beginner programmer would realistically use. I am not sure what shape you want to store your "separate array"s in. I have options below for keeping them in a vector or in the original shape of a.
function nexttwo(row, i)
newarray::Vector{Any} = [row[i]]
for j=1:2
i+=1
if length(row) >= i
push!(newarray, row[i])
else
push!(newarray, nothing)
end
end
return newarray
end
function collectnexttwo(a)
result_collection = []
for i in axes(a,1)
for j in axes(a,2)
row = a[i,:]
newarray = nexttwo(row, j)
push!(result_collection, newarray)
end
end
return result_collection
end
function restoreshape(v, a)
permutedims(reshape(v, reverse(size(a))))
end
julia> a = [1 2 3 4 5; 6 7 8 9 10; 11 12 13 14 15;]
3×5 Matrix{Int64}:
1 2 3 4 5
6 7 8 9 10
11 12 13 14 15
julia> result = restoreshape(collectnexttwo(a), a)
3×5 Matrix{Any}:
Any[1, 2, 3] Any[2, 3, 4] Any[3, 4, 5] Any[4, 5, nothing] Any[5, nothing, nothing]
Any[6, 7, 8] Any[7, 8, 9] Any[8, 9, 10] Any[9, 10, nothing] Any[10, nothing, nothing]
Any[11, 12, 13] Any[12, 13, 14] Any[13, 14, 15] Any[14, 15, nothing] Any[15, nothing, nothing]
I think that you have some problems with the statement of what you want to achieve. That can often make a programming assignment much harder.
Restating what you have already:
I want to iterate through every row
This is pretty easy
for row = 1:size(a)[1]
...
end
For each row, I want each element to be checked
This is where things begin to get squishy? What do you mean by "checked". Let's assume you have some function called checkElement.
With each element, I want to store a separate array that holds the element and the next 2 elements.
How long do you want that separate array to live? Do you just want to hold 3 elements? Or three elements for every cell of the original (i.e. have a 3x5x3 result for a 3x5 input like you show)
Also, what do you want to do about elements 4 and 5 in each row? What values do you want to use for their "next" elements? You could use missing as a value or NaN. Or you could make the result just not contain the problematic inputs.
If you answer these questions, you are likely to find it much easier to write the code you need.

Counting Sort - Why go in reverse order during the insertion?

I was looking at the code for Counting Sort on GeeksForGeeks and during the final stage of the algorithm where the elements from the original array are inserted into their final locations in the sorted array (the second-to-last for loop), the input array is traversed in reverse order.
I can't seem to understand why you can't just go from the beginning of the input array to the end, like so :
for i in range(len(arr)):
output_arr[count_arr[arr[i] - min_element] - 1] = arr[i]
count_arr[arr[i] - min_element] -= 1
Is there some subtle reason for going in reverse order that I'm missing? Apologies if this is a very obvious question. I saw Counting Sort implemented in the same style here as well.
Any comments would be helpful, thank you!
Stability. With your way, the order of equal-valued elements gets reversed instead of preserved. Going over the input backwards cancels out the backwards copying (that -= 1 thing).
To process an array in forward order, the count / index array either needs to be one element larger so that the starting index is 0 or two local variables can be used. Example for integer array:
def countSort(arr):
output = [0 for i in range(len(arr))]
count = [0 for i in range(257)] # change
for i in arr:
count[i+1] += 1 # change
for i in range(256):
count[i+1] += count[i] # change
for i in range(len(arr)):
output[count[arr[i]]] = arr[i] # change
count[arr[i]] += 1 # change
return output
arr = [4,3,0,1,3,7,0,2,6,3,5]
ans = countSort(arr)
print(ans)
or using two variables, s to hold the running sum, c to hold the current count:
def countSort(arr):
output = [0 for i in range(len(arr))]
count = [0 for i in range(256)]
for i in arr:
count[i] += 1
s = 0
for i in range(256):
c = count[i]
count[i] = s
s = s + c
for i in range(len(arr)):
output[count[arr[i]]] = arr[i]
count[arr[i]] += 1
return output
arr = [4,3,0,1,3,7,0,2,6,3,5]
ans = countSort(arr)
print(ans)
Here We are Considering Stable Sort --> which is actually considering the Elements position by position.
For eg if we have array like
arr--> 5 ,8 ,3, 1, 1, 2, 6
0 1 2 3 4 5 6 7 8
count-> 0 2 1 1 0 1 1 0 1
Now we take cummulative sum of all frequencies
0 1 2 3 4 5 6 7 8
count-> 0 2 3 4 4 5 6 6 7
After Traversing the Original array , we prefer from last Since
we want to add Elements on their proper position so when we subtract the index , the Element will be added to lateral position.
But if we start traversing from beginning , then there will be no meaning for taking the cummulative sum since we are not adding according to the Elements placed. We are adding hap -hazardly which can be done even if we not take their cummulative sum.

Why do you need to subtract from size of array? [closed]

Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 8 years ago.
Improve this question
When I try to run the second line without subtracting from the size of the array, it won't work. Why not?
values = [10, 9, 11, 2, 45]
max_element = values.size - 1
first = values[0]
for i in 0..max_element
while first < values[i]
first = values[i]
end
end
p "The largest value is #{first}"
Besides methods on Enumerable or Array such as each, is for the only iterator that loops over a collection of elements?
Because array indices are zero-based, just like in C or Java:
values = [10, 9, 11, 2, 45]
values.size #=> 5
values[0] #=> 10 (1st element)
values[4] #=> 45 (last element)
values[5] #=> nil (this is beyond the last item)
You can use ... (three dots) to exclude the range's end:
for i in 0...values.size
# ...
end
Furthermore, your while should be an if:
if first < values[i]
first = values[i]
end
# or
first = values[i] if first < values[i]
Arrays start their element count at index 0. The values.size gives you the number of elements within the array (which starts with 1 for a non-empty array). Check the following examples:
values = [10 , 9 ]
index = 0 1
size = 2
values = [10 , 9 , 11 , 2 , 45 ]
index = 0 1 2 3 4
size = 5
That's why the last element is always at the index of values.size - 1
Because it will take max_element = 5 (size of values) and when i get to 5, you access values[5] in the while loop which is out of the range of values array

Cycle sort Algorithm

I was browsing through the internet when i found out that there is an algorithm called cycle sort which makes the least number of memory writes.But i am not able to find the algorithm anywhere.How to detect whether a cycle is there or not in an array?
Can anybody give a complete explanation for this algorithm?
The cycle sort algorithm is motivated by something called a cycle decomposition. Cycle decompositions are best explained by example. Let's suppose that you have this array:
4 3 0 1 2
Let's imagine that we have this sequence in sorted order, as shown here:
0 1 2 3 4
How would we have to shuffle this sorted array to get to the shuffled version? Well, let's place them side-by-side:
0 1 2 3 4
4 3 0 1 2
Let's start from the beginning. Notice that the number 0 got swapped to the position initially held by 2. The number 2, in turn, got swapped to the position initially held by 4. Finally, 4 got swapped to the position initially held by 0. In other words, the elements 0, 2, and 4 all were cycled forward one position. That leaves behind the numbers 1 and 3. Notice that 1 swaps to where 3 is and 3 swaps to where 1 is. In other words, the elements 1 and 3 were cycled forward one position.
As a result of the above observations, we'd say that the sequence 4 3 0 1 2 has cycle decomposition (0 2 4)(1 3). Here, each group of terms in parentheses means "circularly cycle these elements forward." This means to cycle 0 to the spot where 2 is, 2 to the spot where 4 is, and 4 to the spot where 0 was, then to cycle 1 to the spot where 3 was and 3 to the spot where 1 is.
If you have the cycle decomposition for a particular array, you can get it back in sorted order making the fewest number of writes by just cycling everything backward one spot. The idea behind cycle sort is to try to determine what the cycle decomposition of the input array is, then to reverse it to put everything back in its place.
Part of the challenge of this is figuring out where everything initially belongs since a cycle decomposition assumes you know this. Typically, cycle sort works by going to each element and counting up how many elements are smaller than it. This is expensive - it contributes to the Θ(n2) runtime of the sorting algorithm - but doesn't require any writes.
here's a python implementation if anyone needs
def cycleSort(vector):
writes = 0
# Loop through the vector to find cycles to rotate.
for cycleStart, item in enumerate(vector):
# Find where to put the item.
pos = cycleStart
for item2 in vector[cycleStart + 1:]:
if item2 < item:
pos += 1
# If the item is already there, this is not a cycle.
if pos == cycleStart:
continue
# Otherwise, put the item there or right after any duplicates.
while item == vector[pos]:
pos += 1
vector[pos], item = item, vector[pos]
writes += 1
# Rotate the rest of the cycle.
while pos != cycleStart:
# Find where to put the item.
pos = cycleStart
for item2 in vector[cycleStart + 1:]:
if item2 < item:
pos += 1
# Put the item there or right after any duplicates.
while item == vector[pos]:
pos += 1
vector[pos], item = item, vector[pos]
writes += 1
return writes
x = [0, 1, 2, 2, 2, 2, 1, 9, 3.5, 5, 8, 4, 7, 0, 6]
w = cycleSort(x)
print w, x

Resources