Selecting from a Hash - ruby

I'm learning Ruby on Codecademy and I'm having trouble with this problem:
Create a new variable, good_movies, and set it equal to the result of
calling .select on movie_ratings, selecting only movies with a rating
strictly greater than 3.
Here's my code:
movie_ratings = {
memento: 3,
primer: 3.5,
the_matrix: 5,
truman_show: 4,
red_dawn: 1.5,
skyfall: 4,
alex_cross: 2,
uhf: 1,
lion_king: 3.5
}
# Add your code below!
good_movies = movie_ratings.each {|k,v| v > 3}
Here is the result:
{:memento=>3, :primer=>3.5, :the_matrix=>5, :truman_show=>4, :red_dawn=>1.5, :skyfall=>4, :alex_cross=>2, :uhf=>1, :lion_king=>3.5}
And this is the error that I'm getting:
Oops, try again. It looks like good_movies includes memento, but it
shouldn't.
"memento" has a value of 3 and I thought that my "v > 3" condition would filter it out; what am I doing wrong?

Use Hash#select to filter as per conditions, not Hash#each.
movie_ratings.select {|k,v| v > 3}
Basically Hash#each returns the receiver on which you called it, and in your case, it the original hash movie_ratings. Indeed it contains memento key, as I said, Hash#each not for filtering purposes. But Hash#select, will filter memento with its value out from the output Hash, thus your code will not give any objections.

You must have change each for select like this: good_movies = movie_ratings.select {|k,v| v > 3}

Related

Access `self` of an object through the parameters

Let's say I want to access an element of an array at a random index this way:
[1, 2, 3, 4].at(rand(4))
Is there a way to pass the size of the array like the following?
[1, 2, 3, 4].at(rand(le_object.self.size))
Why would I do that?--A great man once said:
Science isn't about why, it is about why not.
Not recommended, but instance_eval would somehow work:
[1, 2, 3, 4].instance_eval { at(rand(size)) }
And you can also break out of tap:
[1, 2, 3, 4].tap { |a| break a.at(rand(a.size)) }
There's an open feature request to add a method that yields self and returns the block's result. If that makes it into Ruby, you could write:
[1, 2, 3, 4].insert_method_name_here { |a| a.at(rand(a.size)) }
No, you can't do that. Receiver of a method (that array) is not accessible by some special name at the call site. Your best bet is assigning a name to that object.
ary = [1, 2, 3, 4]
ary.at(rand(ary.size))
Of course, if all you need is a random element, then .sample should be used. Which does not require evaluation of any arguments at the call site and its self is the array.
You can use instance_eval to execute ruby code with the binding of the array variable
[1, 2, 3, 4].instance_eval { at(rand(size)) }
Assuming you are interested in a random element as Array#at returns an element at given index, you can use Array#sample to pick a random element from an array.
[1,2,3,4].sample
#=> 3
If you do not want to use instance_eval (or any form of eval), then, you can add a method to Array class by monkey patching - generally speaking, I am not sure whether it's a wise idea to monkey patch though
class Array
def random_index
rand(size)
end
end
["a","b","c","d"].random_index
#=> 2
You could do something similar with lambda:
getrand = ->(x) { x[rand(x.count)] }
getrand.call [1,2,3]
# => 2

getting differences between values in an array

I want to write an Array method in ruby that takes the successive values in the array and returns their differences as a new array (unshifting a '0' in at the beginning).
So feeding the array [4,7,11,16] into the method returns a new array [4,3,4,5].
1) does such a method already exist?
If not, then I think I know how to write it. However,
2) does a method already exist which allows me to test the input array and make sure it only consists of integers and/or floats?
Again, if not, I think I know how to write one.
p [4,7,11,16].unshift(0).each_cons(2).map{|a,b| b-a} # => [4, 3, 4, 5]
Keep it simple:
arr = [4,7,11,16]
last = 0
arr.map { |e| new=e-last; last=e; new }
#=> [4, 3, 4, 5]
Another way:
a = [arr.first]
enum = arr.each
loop do
a << -enum.next + enum.peek
end
a
#=> [4, 3, 4, 5]
Enumerator#peek raises a StopIteration exception when enum is at its last element. Kernel#loop handles the exception by breaking from the loop.
Regarding the first method, I am not aware of any such method in the Ruby Array class.
Regarding the second one, you can do it as explained in this answer:
your_array.all? {|i| i.is_a? Numeric }

Ruby remove nil values from array with .reject

I have an array:
scores = [1, 2, 3, "", 4]
And I want to remove all blank values. But when I run this:
puts scores.reject(&:empty?)
I get an error:
undefined method `empty' for 1:Fixnum
How can I remove values that are not integers from my array in a one step process? I am using Ruby 1.9.3.
To reject only nil would be:
array.compact
If you want to remove blank values, you should use blank?: (requires Rails / ActiveSupport)
scores.reject(&:blank?)
#=> [1, 2, 3, 4]
"", " ", false, nil, [], and {} are blank.
It is as simple as:
scores.grep(Integer)
Note that if you plan to map the values, you can do that in a block after:
scores.grep(Integer){|x| x+1 }
Bonus if you want to do the same thing, but your numbers are strings:
scores.grep(/\d+/){|x|x.to_i}
Try this :
scores.select{|e| e.is_a? Integer}
# => [1, 2, 3, 4]
If you really need reject nil only, so it can be done like this:
scores.reject(&:nil?)
scores = [1, 2, 3, "", 4, nil]
scores.reject{|s| s.to_s == ''}
# => [1, 2, 3, 4]
This Worked for me
scores.reject!{|x| x.to_s.empty?}
scores.select{|score| score.is_a? Fixnum}
or, as Fixnum inherits from Integer, you can also go for
scores.select{|score| score.is_a? Integer)
...if that seems more descriptive.
Array and Enumerable tend to offer many ways of doing the same thing.
&:empty? will work for hashes, arrays, and strings, but not numbers. The method you use in reject must be valid for all items in a list. &:blank? will work fine for this reason.

How to iterate over part of a hash in Ruby?

h = Hash.new
(1..100).each { |v| h.store(v * 2, v*v) }
What is the best way to iterate over a given part of the hash without using the keys? For example, from element 10 to element 20? Using Ruby 1.9.3.
EDIT - In response to Dave's comment:
Originally I wanted to access the data through keys (hence the hash). But I also want to iterate by element number. BTW, each element is a hash.
So, what is the best way to design a hash of hashes or array of hashes that can be iterated by element number or accessed by key? The data looks like the following. There are missing dates.
6/23/2011 -> 5, 6, 8, 3, 6
6/26/2011 -> 6, 8, 4, 8, 5
6/27/2011 -> 8, 4, 3, 2, 7
If I understand what you're asking for, you can iterate over a portion of your hash as follows. This gives you the 1001st through 2000th values:
h.keys[1000..1999].each do |key|
# Do something with h[key]
end
I think you better use Array for that (Hash in Ruby 1.9.3 are ordered but the access method is the keys). So:
a = h.values
# or
a = h.to_a
Convert it to an array, then slice it:
h.to_a[10..20].each { |k, v| do_stuff }
Note that before Ruby 1.9, the order of elements in a hash are not guaranteed, so this will not necessarily work as you expect.
Alternatively, you could use each_with_index and skip over the unwanted elements:
h.each_with_index do |(k, v), i|
next unless (10..20).include?(i)
# do stuff
end
h = Hash.new
(1..100).each { |v| h.store(v * 2, v*v) }
#for an array of arrays
h.drop(9).take(10) #plus an optional block
#if the slice must be a hash:
slice = Hash[h.drop(9).take(10)]
But if this is an often repeating operation you might be better off using a database.

Elegantly implementing 'map (+1) list' in ruby

The short code in title is in Haskell, it does things like
list.map {|x| x + 1}
in ruby.
While I know that manner, but what I want to know is, is there any more elegant manners to implement same thing in ruby like in Haskell.
I really love the to_proc shortcut in ruby, like this form:
[1,2,3,4].map(&:to_s)
[1,2,3,4].inject(&:+)
But this only accept exactly matching argument number between the Proc's and method.
I'm trying to seek a way that allow passing one or more arguments extra into the Proc, and without using an useless temporary block/variable like what the first demonstration does.
I want to do like this:
[1,2,3,4].map(&:+(1))
Does ruby have similar manners to do this?
If you just want to add one then you can use the succ method:
>> [1,2,3,4].map(&:succ)
=> [2, 3, 4, 5]
If you wanted to add two, you could use a lambda:
>> add_2 = ->(i) { i + 2 }
>> [1,2,3,4].map(&add_2)
=> [3, 4, 5, 6]
For arbitrary values, you could use a lambda that builds lambdas:
>> add_n = ->(n) { ->(i) { i + n } }
>> [1,2,3,4].map(&add_n[3])
=> [4, 5, 6, 7]
You could also use a lambda generating method:
>> def add_n(n) ->(i) { i + n } end
>> [1,2,3,4].map(&add_n(3))
=> [4, 5, 6, 7]
Use the ampex gem, which lets you use methods of X to build up any proc one one variable. Here’s an example from its spec:
["a", "b", "c"].map(&X * 2).should == ["aa", "bb", "cc"]
You can't do it directly with the default map. However it's quite easy to implement a version that supports this type of functionality. As an example Ruby Facets includes just such a method:
require 'facets/enumerable'
[1, 2, 3, 4].map_send(:+, 10)
=> [11, 12, 13, 14]
The implementation looks like this:
def map_send(meth, *args, &block)
map { |e| e.send(meth, *args, &block) }
end
In this particular case, you can use the following:
[1, 2, 3, 4].map(&1.method(:+))
However, this only works because + is not associative. It wouldn't work for -, for example.
Ruby hasn't built-in support for this feature, but you can create your own extension or use small gem 'ampex'. It defines global variable X with extended 'to_proc' functionality.
It gives you possibility to do that:
[1,2,3].map(&X.+(1))
Or even that:
"alpha\nbeta\ngamma\n".lines.map(&X.strip.upcase)
If you just want to add 1, you can use next or succ:
[1,2,3,4].map(&:next)
[1,2,3,4].map(&:succ)

Resources