infinite enumerator rewind - ruby

I have a function that generates an enumerator in the following manner:
def create_example_enumerator(starting_value)
current = starting_value
e = Enumerator.new do |y|
loop do
current += 1
y << current
end
end
end
The current behavior is pretty straightforward.
> e = create_example_enumerator(0)
#<Enumerator: details>
> e.next
1
> e.next
2
> e.rewind
#<Enumerator: details>
> e.next
3
I would like e.rewind to reset the enumerator back to it's starting value.
Is there a nice way to do that while still using an infinite enumerator?

This should work:
n = Enumerator.new do |y|
number = 1
loop do
y.yield number
number += 1
end
end
n.next #=> 1
n.next #=> 2
n.next #=> 3
n.rewind
n.next #=> 1

Related

How can I pass in a block to my "bubble sort" method?

The below code is my newbie take on a bubble sort method.
#For each element in the list, look at that element and the element
#directly to it's right. Swap these two elements so they are in
#ascending order.
def bubble_sort (array)
a = 0
b = 1
until (array.each_cons(2).all? { |a, b| (a <=> b) <= 0}) == true do
sort = lambda {array[a] <=> array[b]}
sort_call = sort.call
loop do
case sort_call
when -1 #don't swap
a += 1
b += 1
break
when 0 #don't swap
a += 1
b += 1
break
when 1 #swap
array.insert(a,array.delete_at(b))
a += 1
b += 1
break
else #end of array, return to start
a = 0
b = 1
break
end
end
end
puts array.inspect
end
array = [4, 2, 5, 6, 3, 23, 5546, 234, 234, 6]
bubble_sort(array)
I want to be able to alter this method so that it takes a block of code as an argument and uses this to determine how it sorts.
For example:
array = ["hello", "my", "name", "is", "daniel"]
bubble_sort(array) {array[#a].length <=> array[#b].length}
(When I've tried this I've turned a and b into instance variables throughout the code.)
I have tried using yield but I get undefined method 'length' for nil:NilClass once the end of the array is reached. I've tried adding in things such as
if array[#b+1] == nil
#a = 0
#b = 1
end
This helps but I still end up with weird problems like infinite loops or not being able to sort more than certain amount of elements.
Long story short, I have been at this for hours. Is there a simple way to do what I want to do? Thanks.
The way you're calling your lambda is a bit odd. It's actually completely unnecessary. I refactored your code and cleaned up a bit of the redundancy. The following works for me:
def sorted?(arr)
arr.each_cons(2).all? { |a, b| (a <=> b) <= 0 }
end
def bubble_sort (arr)
a = 0
b = 1
until sorted?(arr) do
# The yield call here passes `arr[a]` and `arr[b]` to the block.
comparison = if block_given?
yield(arr[a], arr[b])
else
arr[a] <=> arr[b]
end
if [-1, 0, 1].include? comparison
arr.insert(a, arr.delete_at(b)) if comparison == 1
a += 1
b += 1
else
a = 0
b = 1
end
end
arr
end
sample_array = [4, 2, 5, 6, 3, 23, 5546, 234, 234, 6]
# Sanity check:
100.times do
# `a` is the value of `arr[a]` in our function above. Likewise for `b` and `arr[b]`.
print bubble_sort(sample_array.shuffle) { |a, b| a <=> b }, "\n"
end
EDIT
A cleaner version:
# In place swap will be more efficient as it doesn't need to modify the size of the arra
def swap(arr, idx)
raise IndexError.new("Index #{idx} is out of bounds") if idx >= arr.length || idx < 0
temp = arr[idx]
arr[idx] = arr[idx + 1]
arr[idx + 1] = temp
end
def bubble_sort(arr)
loop do
sorted_elements = 0
arr.each_cons(2).each_with_index do |pair, idx|
comparison = if block_given?
yield pair.first, pair.last
else
pair.first <=> pair.last
end
if comparison > 0
swap(arr, idx)
else
sorted_elements += 1
end
end
return arr if sorted_elements >= arr.length - 1
end
end
# A simple test
sample_array = [4, 2, 2, 2, 2, 2, 5, 5, 6, 3, 23, 5546, 234, 234, 6]
sample_str_array = ["a", "ccc", "ccccc"]
100.times do
print bubble_sort(sample_array.shuffle) { |a, b| a <=> b }, "\n"
print bubble_sort(sample_str_array.shuffle) { |a, b| a.length <=> b.length }, "\n"
end
You're not too far off. Just a few things:
Make your function take a block argument
def bubble_sort (array, &block)
Check to see if the user has provided a block
if block_given?
# Call user's comparator block
else
# Use the default behavior
end
Call the user's comparator block
block.call(a, b)
In the user-provided block, accept block params for the elements to compare
bubble_sort(array) {|a,b| a.length <=> b.length}
That should put you in the right ballpark.

Defining my_times Enumerator based on my_each Enumerator?

Say that I have my own implementation of each:
class Array
def my_each
c = 0
until c == size
yield(self[c])
c += 1
end
self
end
end
How would I do my own implementation of times by using my_each? Here is my approach:
class Integer
def my_times
Array.new(self) { |i| i }.my_each do |el|
yield el
end
end
end
But I don't particularly like it because I am creating an Array. But, is there any other way I could accomplish this?
You could do it like this:
class Integer
def my_times
return (0...self).to_enum unless block_given?
(0...self).each { |i| yield i }
end
end
5.my_times { |i| puts i*i }
0
1
4
9
16
5.my_times #=> #<Enumerator: 0...5:each>
I have used Range#each. To use Array#my_each we'd have to convert the range to an array:
[*(0...self)].my_each { |i| yield i }
Recall that Integer#times returns an enumerator if no block is given. The same is true of Array#each; you need to fix my_each for it to be equivalent to Array#each.
You don't need each or my_each, however:
class Integer
def my_times
return (0...self).to_enum unless block_given?
i = 0
while(i < self) do
yield i
i += 1
end
end
end
5.my_times { |i| puts i*i }
0
1
4
9
16
5.my_times #=> #<Enumerator: 0...5:each>

Ruby: how do I pass the element and its index from an array?

I have the following array:
arr = [1,2,"car"]
arr.each do |e|
puts e
end
#=> 1
2
car
But how do I make a "put e" that also shows its index number?
arr = [1,2,"car"]
arr.each_with_index() do |e,i|
puts "#{e} is at index #{i}"
end
# >> 1 is at index 0
# >> 2 is at index 1
# >> car is at index 2
arr = [1,2,"car"]
arr.each_with_index do |e, index|
puts index, e
end
To get only index:
arr = [1,2,"car"]
arr.each_index do |index|
puts index
end

Filter arrays with bitmask or other array in Ruby

I was wondering if there was an Array method in Ruby that allows to filter an array based on another array or a bitmask.
Here is an example and a quick implementation for illustration purposes:
class Array
def filter(f)
res = []
if f.is_a? Integer
(0...self.size).each do |i|
res << self[i] unless f[i].nil? || 2**i & f == 0
end
else
(0...self.size).each do |i|
res << self[i] unless f[i].nil? || f[i] == 0
end
end
return res
end
end
Example:
%w(a b c).filter([1, 0, 1]) ==> ['a', 'c']
%w(a b c).filter(4) ==> ['c']
%w(a b c).filter([1]) ==> ['a']
Thanks!
In ruby 1.9 Fixnum#[] gives you bit values at a particular position, so it will work for both integers and arrays. I'm thinking something like this:
class Array
def filter f
select.with_index { |e,i| f[i] == 1 }
end
end
%w(a b c).filter([1, 0, 1]) #=> ['a', 'c']
%w(a b c).filter(4) #=> ['c']
%w(a b c).filter(5) #=> ['a', c']
%w(a b c).filter([1]) #=> ['a']
class Array
def filter(f)
f = f.to_s(2).split("").map(&:to_i) unless Array === f
reverse.reject.with_index{|_, i| f[-i].to_i.zero?}
end
end

Find most common string in an array

I have this array, for example (the size is variable):
x = ["1.111", "1.122", "1.250", "1.111"]
and I need to find the most commom value ("1.111" in this case).
Is there an easy way to do that?
Tks in advance!
EDIT #1: Thank you all for the answers!
EDIT #2: I've changed my accepted answer based on Z.E.D.'s information. Thank you all again!
Ruby < 2.2
#!/usr/bin/ruby1.8
def most_common_value(a)
a.group_by do |e|
e
end.values.max_by(&:size).first
end
x = ["1.111", "1.122", "1.250", "1.111"]
p most_common_value(x) # => "1.111"
Note: Enumberable.max_by is new with Ruby 1.9, but it has been backported to 1.8.7
Ruby >= 2.2
Ruby 2.2 introduces the Object#itself method, with which we can make the code more concise:
def most_common_value(a)
a.group_by(&:itself).values.max_by(&:size).first
end
As a monkey patch
Or as Enumerable#mode:
Enumerable.class_eval do
def mode
group_by do |e|
e
end.values.max_by(&:size).first
end
end
["1.111", "1.122", "1.250", "1.111"].mode
# => "1.111"
One pass through the hash to accumulate the counts. Use .max() to find the hash entry with the largest value.
#!/usr/bin/ruby
a = Hash.new(0)
["1.111", "1.122", "1.250", "1.111"].each { |num|
a[num] += 1
}
a.max{ |a,b| a[1] <=> b[1] } # => ["1.111", 2]
or, roll it all into one line:
ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] } # => ["1.111", 2]
If you only want the item back add .first():
ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] }.first # => "1.111"
The first sample I used is how it would be done in Perl usually. The second is more Ruby-ish. Both work with older versions of Ruby. I wanted to compare them, plus see how Wayne's solution would speed things up so I tested with benchmark:
#!/usr/bin/env ruby
require 'benchmark'
ary = ["1.111", "1.122", "1.250", "1.111"] * 1000
def most_common_value(a)
a.group_by { |e| e }.values.max_by { |values| values.size }.first
end
n = 1000
Benchmark.bm(20) do |x|
x.report("Hash.new(0)") do
n.times do
a = Hash.new(0)
ary.each { |num| a[num] += 1 }
a.max{ |a,b| a[1] <=> b[1] }.first
end
end
x.report("inject:") do
n.times do
ary.inject(Hash.new(0)){ |h,i| h[i] += 1; h }.max{ |a,b| a[1] <=> b[1] }.first
end
end
x.report("most_common_value():") do
n.times do
most_common_value(ary)
end
end
end
Here's the results:
user system total real
Hash.new(0) 2.150000 0.000000 2.150000 ( 2.164180)
inject: 2.440000 0.010000 2.450000 ( 2.451466)
most_common_value(): 1.080000 0.000000 1.080000 ( 1.089784)
You could sort the array and then loop over it once. In the loop just keep track of the current item and the number of times it is seen. Once the list ends or the item changes, set max_count == count if count > max_count. And of course keep track of which item has the max_count.
You could create a hashmap that stores the array items as keys with their values being the number of times that element appears in the array.
Pseudo Code:
["1.111", "1.122", "1.250", "1.111"].each { |num|
count=your_hash_map.get(num)
if(item==nil)
hashmap.put(num,1)
else
hashmap.put(num,count+1)
}
As already mentioned, sorting might be faster.
Using the default value feature of hashes:
>> x = ["1.111", "1.122", "1.250", "1.111"]
>> h = Hash.new(0)
>> x.each{|i| h[i] += 1 }
>> h.max{|a,b| a[1] <=> b[1] }
["1.111", 2]
It will return most popular value in array
x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[0]
IE:
x = ["1.111", "1.122", "1.250", "1.111"]
# Most popular
x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[0]
#=> "1.111
# How many times
x.group_by{|a| a }.sort_by{|a,b| b.size<=>a.size}.first[1].size
#=> 2

Resources