Iterator does not work in a simple loop - ruby

Very annoying mistake, but I'm still learning, so please be helpful.
I read a file, make a table and iterate it. Was wondering why my iteration incrementation does not work in this type of loop.
nrOfWordsInOneLine_array = Array.new { Hash.new }
iterator = 0
nrOfWordsInOneLine_array.each_with_index do |i, j|
iterator =+ 1
puts "Word in line #{j+1} #{iterator} is: #{i.length} and the longest one is #{i.max_by(&:length)} with #{i.max_by(&:length).length} letters"
end
output:
Word in line 1 1 is: 8 and the longest one is First with 5 letters
Word in line 2 1 is: 6 and the longest one is Second with 6 letters
Word in line 3 1 is: 4 and the longest one is Fourth with 6 letters
Word in line 4 1 is: 2 and the longest one is Fifth with 5 letters

iterator =+ 1 You have the + and = around the wrong way.
You want iterator += 1, right now you are setting iterator to +1 which is 1.

Related

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.

Count characters starting at zero?

I need to write a for-each loop that lists each character in
mystery_string with its index. Example below:
mystery_string= "Olivia," output would be:
0 O
1 l
2 i
3 v
4 i
5 a
I cannot use the range function on this problem.
This is my code, but the number starts at 1. What am I doing wrong?
mystery_string = "CS1301"
count = 0
for current_letter in mystery_string:
count = count + 1
print (count , current_letter)
I have been getting this as output:
1 C
2 S
3 1
4 3
5 0
6 1
but it needs to start at zero.
Just add the count (count += 1) after you print in the for loop
Note: Also, please format your code in a code block surrounded with a tick(`) or multiline code with 3 tick (```)
The pythonic way is to use enumerate() in such a case. This way you'll get both the index and the content of your string.
mystery_string = "CS1301"
for count, current_letter in enumerate(mystery_string):
print (count , current_letter)

Boyer-Moore Algorithm: Reaching the End of the Text

I'm working through this algorithm and the pattern and text are not matching up.
The text is: AADBCCAAA
The pattern is: CCAAA
I've created both the bad-symbol table and good-suffix table.
Bad Symbol:
! A C (! represents letters not in the pattern)
5 1 3
Good-suffix:
k d2
1 2
2 6
3 6
4 6
5 6
As for my searching:
AADBCCAAA
CCAAA Since there is no match, shift 3 because C causes the mismatch
This lines up the right-most A in the pattern with the 2nd to last A in the text. This means
d1 = 3-2 = 1 and d2 = 6. The max of the two is 6 so shift 6.
With Boyer-Moore, does this mean since you can't shift 6, it will just compare the pattern with the end of the text and find the match or am I doing something wrong?

Ruby file reading

I have a problem reading a file in ruby.
I am trying to read each line of a file, split it based on characters, and store that into an array. That array, which corresponds to each line, has information. I want to check if that array includes the characters "u" "d" "l" or "r" as you can see below.
IF that line doesn't include ANY of those characters, I increase a count variable by one.
The count -= 1 just takes into account a base case.
My problem is that this gives me a wrong count. For example with a text file that reads:
4 0 0 3 3
0 0 d 0.391538986557049
0 1 ur 63.1258159853081 3.14882640637611
0 2 rd 0.0148854629087619 0.019301544005463
0 3 u 15.6415340291405
count is supposed to be 0.
def compute_closed(file)
count = 0
while line = file.gets do
array = line.split(//)
answer = array.include?("u" || "d" || "l" || "r")
if answer != true
count += 1
end
end
count -= 1
puts count
end
Maybe you have a reason for splitting the line up into bits, but if you're just checking for those characters somewhere in the line, why not use a regex?
def compute_closed(file)
count = 0
while line = file.gets do
count += 1 if line =~ /[udlr]/
end
count -= 1
puts count
end
If you absolutely need to split the lines up by character, then you may want to use sets instead of arrays:
def compute_closed(file)
count = 0
while line = file.gets do
cmp_set = Set.new ['u', 'd', 'l', 'r']
input_set = Set.new(line.split(//))
if input_set.intersection(cmp_set).size == 0
count += 1
end
end
count -= 1
puts count
end
Edit: after posting I see my answer is essentially the same as #Philip's, but I'll leave it up for the slightly different treatment.
There are many ways to do this. Here's another:
File.read('f1').each_line.reduce(0) {|t,s| t + (s =~ /[udlr]/ ? 0 : 1)} - 1
Let's try it:
text =<<_
Now is the time
for all good
Rubiests to
spend some
time in Hawaii.
_
File.write('f1', text)
File.read('f1').each_line.reduce(0) {|t,s| t+(s =~ /[udlr]/ ? 0 : 1)} - 1 #=> 1
It returns 2 - 1 => 1 because if finds a 'u,' 'd', 'l' or 'r' in all but the the first and last rows.
Initially, I had
File.read(fname).each_line.each_with_object(0) {|s,t|
t += 1 unless s =~ /[udlr]/ } - 1
but t would not increment. I was puzzled, so emailed my friend #ArupRakshit, who I can always count on to know the answer, or dig until he finds it. It turns out that in
...each_with_object(memo) {|s,memo|
memo must be a mutable object, an important difference between that method and reduce/inject (which is not made clear in the Ruby docs for Enumerable#each_with_object). Thanks, Arup.

Ruby: increment all integers in a string by +1

I am looking for a succinct way to increment all the integers found in a string by +1 and return the full string.
For example:
"1 plus 2 and 10 and 100"
needs to become
"2 plus 3 and 11 and 101"
I can find all the integers very easily with
"1 plus 2 and 10 and 100".scan(/\d+/)
but I'm stuck at this point trying to increment and put the parts back together.
Thanks in advance.
You could use the block form of String#gsub:
str = "1 plus 2 and 10 and 100".gsub(/\d+/) do |match|
match.to_i + 1
end
puts str
Output:
2 plus 3 and 11 and 101
The gsub method can take in a block, so you can do this
>> "1 plus 2 and 10 and 100".gsub(/\d+/){|x|x.to_i+1}
=> "2 plus 3 and 11 and 101"
The thing with your regex is that it doesn't preserve your original string in the chain in order to put it back. What I did was to split it using spaces, detect which are words or integers using w.to_i != 0 (not counting 0 as an integer, you might want to improve this), add one, and join it back:
s = "1 plus 2 and 10 and 100"
s.split(" ").map{ |e| if (e.to_i != 0) then e.to_i+1 else e end }.join(" ")
=> "2 plus 3 and 11 and 101"

Resources