Accessing the last key–value pair in a Ruby (1.9) hash - ruby

As of Ruby 1.9, hashes retain insertion order which is very cool. I want to know the best way to access the last key–value pair.
I've written some code which does this:
hash.values.last
This works and is very easy to comprehend, but perhaps it's possible to access the last value directly, rather that via an intermediary (the array of values). Is it?

Hash have a "first" method, but that return the first pair in array mode, for last, you can try:
my_hash.to_a.last
this return last pair in array mode like "first method"

One more alternative that I'm using myself:
hash[hash.keys.last]
which works out better when you want to directly assign a value onto the last element of the hash:
2.4.1 :001 > hash = {foo: 'bar'}
=> {:foo=>"bar"}
2.4.1 :002 > hash[hash.keys.last] = 'baz'
=> "baz"
2.4.1 :003 > hash.values.last = 'bar'
NoMethodError: undefined method `last=' for ["baz"]:Array
Did you mean? last
from (irb):3
from /home/schuylr/.rvm/rubies/ruby-2.4.1/bin/irb:11:in `<main>'

Nothing built in, no. But you could monkey-patch one if you were so inclined (not usually recommended, of course):
class Hash
def last_value
values.last
end
end
And then:
hash.last_value

I just did this for a very large hash:
hash.reverse_each.with_index do |(_, value), index|
break value if (index == 0)
end

Related

is there a way to get a random element from an array and also delete it just that single element

I want:
1.9.3p392 :015 > a=["birds","things","people","people"]
=> ["birds", "things", "people","people"]
1.9.3p392 :016 > a.sample
=> "people"
1.9.3p392 :017 > a
=> ["birds", "things","people"]
1.9.3p392 :018 >
but doesn't look like sample supports this. Anything I'm missing in sample's arguments? I'm aware I could I could delete with what is returned but that will delete ALL the members that are that value not just that single instance.
thx
Here is a more traditional version I initially suggested which removes the element by index. This method mutates the original array, but also preserves order.
a = ["birds","things","people","people"]
i = rand(a.size)
# delete_at returns the element removed, or nil
elm = a.delete_at(i)
Here is another solution that doesn't have side-effects (it utilizes a one of the sample-size forms). This approach changes the order of the remaining elements and may be "less efficient" for large arrays.
a = ["birds","things","people","people"]
elm, *rest = a.sample(a.size)
I actually would not use the 2nd solution and would manually duplicate the array first if that is what I wanted - after reviewing it, it seems too "clever" and convoluted.
You could do this:
a = ["birds","things","people","people"]
a.delete_at(a.find_index(a.sample))

ruby 2.0 named parameters from a hash

If I have a method in ruby that takes named arguments...
def smoosh(first: nil, second: nil)
first + second
end
Whats the easiest way to pass a hash to that method if the keys match:
params = { first: 'peanut', second: 'butter' }
smoosh(params)
The above produces an argument error.
Update:
It seems like this might be an issue with how Sinatra parameters work.
When I do:
get 'a_sinatra_route' do
hash = params.clone
hash.symbolize_keys!
smoosh(hash)
end
It works fine. It does not work when just passing the params in by themselves. (even though you can access the individual params with the symbol key params[:attr])
Seems to work just fine for me.
2.0.0p0 :007 > def smoosh(first: nil, second: nil)
2.0.0p0 :008?> first + second
2.0.0p0 :009?> end
=> nil
2.0.0p0 :010 > params = { first: 'peanut', second: 'butter' }
=> {:first=>"peanut", :second=>"butter"}
2.0.0p0 :012 > smoosh(params)
=> "peanutbutter"
If your function is using keyword arguments, you'll need to use ** (double splat). The ** (introduced in Ruby 2.0) acts like the original * operator, but can be used with Hashes (see also: another good resource):
def smoosh(first: nil, second: nil)
first + second
end
params = { first: 'double', second: 'splat' }
smoosh(**params)
=> "doublesplat"
It's throwing an ArgumentError because you're passing in one hash to a method that takes two arguments - even though the hash has two key/value pairs, it's still just one argument!
In this situation, you can try:
smoosh(params[:first], params[:second])
To pass in the values.

Array returning Fixnum instead of String

I have an array of arrays similar to:
[["Rosalind_0498", "AAATAAA"], ["Rosalind_2391", "AAATTTT"]]
I I want to get the letter of the first array's second element I would expect to use array[0][1][-1]
This instead of returning 'A' returns 65, it's probably something simple to do with ruby arrays but I'm not sure why it is happening, can someone point me in the right direction?
UPDATE:
Is there a better way to do it then array[0][1][-1..-1]?
Prior to Ruby 1.9, accessing a string char with [] would get you the ascii value of this char.
Just use this in ruby 1.8:
array[0][1][-1].chr
what version of ruby are you using?
2.0.0p0 :001 > a = [["Rosalind_0498", "AAATAAA"], ["Rosalind_2391", "AAATTTT"]]
=> [["Rosalind_0498", "AAATAAA"], ["Rosalind_2391", "AAATTTT"]]
2.0.0p0 :002 > a[0][1][0]
=> "A"
You can try the below:
p [["Rosalind_0498", "AAATAAA"], ["Rosalind_2391", "AAATTTT"]].flatten[1].chr #=> "A"

Search ruby hash for empty value

I have a ruby hash like this
h = {"a" => "1", "b" => "", "c" => "2"}
Now I have a ruby function which evaluates this hash and returns true if it finds a key with an empty value. I have the following function which always returns true even if all keys in the hash are not empty
def hash_has_blank(hsh)
hsh.each do |k,v|
if v.empty?
return true
end
end
return false
end
What am I doing wrong here?
Try this:
def hash_has_blank hsh
hsh.values.any? &:empty?
end
Or:
def hash_has_blank hsh
hsh.values.any?{|i|i.empty?}
end
If you are using an old 1.8.x Ruby
I hope you're ready to learn some ruby magic here. I wouldn't define such a function globally like you did. If it's an operation on a hash, than it should be an instance method on the Hash class you can do it like this:
class Hash
def has_blank?
self.reject{|k,v| !v.nil? || v.length > 0}.size > 0
end
end
reject will return a new hash with all the empty strings, and than it will be checked how big this new hash is.
a possibly more efficient way (it shouldn't traverse the whole array):
class Hash
def has_blank?
self.values.any?{|v| v.nil? || v.length == 0}
end
end
But this will still traverse the whole hash, if there is no empty value
I've changed the empty? to !nil? || length >0 because I don't know how your empty method works.
If you just want to check if any of the values is an empty string you could do
h.has_value?('')
but your function seems to work fine.
I'd consider refactoring your model domain. Obviously the hash represents something tangible. Why not make it an object? If the item can be completely represented by a hash, you may wish to subclass Hash. If it's more complicated, the hash can be an attribute.
Secondly, the reason for which you are checking blanks can be named to better reflect your domain. You haven't told us the "why", but let's assume that your Item is only valid if it doesn't have any blank values.
class MyItem < Hash
def valid?
!invalid?
end
def invalid?
values.any?{|i| i.empty?}
end
end
The point is, if you can establish a vocabulary that makes sense in your domain, your code will be cleaner and more understandable. Using a Hash is just a means to an end and you'd be better off using more descriptive, domain-specific terms.
Using the example above, you'd be able to do:
my_item = MyItem["a" => "1", "b" => "", "c" => "2"]
my_item.valid? #=> false

hash['key'] to hash.key in Ruby

I have a a hash
foo = {'bar'=>'baz'}
I would like to call foo.bar #=> 'baz'
My motivation is rewriting an activerecord query into a raw sql query (using Model#find_by_sql). This returns a hash with the SELECT clause values as keys. However, my existing code relies on object.method dot notation. I'd like to do minimal code rewrite. Thanks.
Edit: it appears Lua has this feature:
point = { x = 10, y = 20 } -- Create new table
print(point["x"]) -- Prints 10
print(point.x) -- Has exactly the same meaning as line above
>> require 'ostruct'
=> []
>> foo = {'bar'=>'baz'}
=> {"bar"=>"baz"}
>> foo_obj = OpenStruct.new foo
=> #<OpenStruct bar="baz">
>> foo_obj.bar
=> "baz"
>>
What you're looking for is called OpenStruct. It's part of the standard library.
A good solution:
class Hash
def method_missing(method, *opts)
m = method.to_s
if self.has_key?(m)
return self[m]
elsif self.has_key?(m.to_sym)
return self[m.to_sym]
end
super
end
end
Note: this implementation has only one known bug:
x = { 'test' => 'aValue', :test => 'bar'}
x.test # => 'aValue'
If you prefer symbol lookups rather than string lookups, then swap the two 'if' condition
Rather than copy all the stuff out of the hash, you can just add some behaviour to Hash to do lookups.
If you add this defintion, you extend Hash to handle all unknown methods as hash lookups:
class Hash
def method_missing(n)
self[n.to_s]
end
end
Bear in mind that this means that you won't ever see errors if you call the wrong method on hash - you'll just get whatever the corresponding hash lookup would return.
You can vastly reduce the debugging problems this can cause by only putting the method onto a specific hash - or as many hashes as you need:
a={'foo'=>5, 'goo'=>6}
def a.method_missing(n)
self[n.to_s]
end
The other observation is that when method_missing gets called by the system, it gives you a Symbol argument. My code converted it into a String. If your hash keys aren't strings this code will never return those values - if you key by symbols instead of strings, simply substitute n for n.to_s above.
There are a few gems for this. There's my recent gem, hash_dot, and a few other gems with similar names I discovered as I released mine on RubyGems, including dot_hash.
HashDot allows dot notation syntax, while still addressing concerns about NoMethodErrors addressed by #avdi. It is faster, and more traversable than an object created with OpenStruct.
require 'hash_dot'
a = {b: {c: {d: 1}}}.to_dot
a.b.c.d => 1
require 'open_struct'
os = OpenStruct.new(a)
os.b => {c: {d: 1}}
os.b.c.d => NoMethodError
It also maintains expected behavior when non-methods are called.
a.non_method => NoMethodError
Please feel free to submit improvements or bugs to HashDot.

Resources