A way to select maximal values from an array - ruby

This will return the first instance of the longest string in an array:
["abcd","efgh","ijk"].max_by { |x| x.length } # => "abcd"
Similarly to this, is there a nice way to get an array of all strings with the maximal length?
["abcd","efgh","ijk"].some_trick ... # => ["abcd","efgh"]

Here we go :
["abcd","efgh","ijk"].group_by(&:size).max.last #=> ["abcd","efgh"]
Explanation :
Enumerable#group_by gives a hash containing each unique size of strings contained in the array as keys, and the matching strings as values => {4=>["abcd", "efgh"], 3=>["ijk"]}
Enumerable#max applied on a Hash will give us the highest key with its matching values, in an Array like this : [key, values] => [4, ["abcd", "efgh"]]
Array#last will give us the last element of the array ... => ["abcd", "efgh"]

Related

Slice string from end in Ruby

How can I split a string into multiple substrings of equal length but from back?
For example if string is: "ABCDEFGH", then I want an array of each string of length 3 as:
["FGH", "CDE", "AB"]
I think that this does what you're asking:
> "ABCDEFGH".reverse.scan(/.{1,3}/).each { |x| x.reverse! }
=> ["FGH", "CDE", "AB"]
Here's a quick explanation:
.reverse reverses the string so that it is "HGFEDCBA" instead of "ABCDEFGH".
.scan(/.{1,3}/) converts the string into an array with each element of the array containing 3 characters (if the string isn't divisible by 3 then the last element of the array may have 1 or 2 characters).
.each { |x| x.reverse! } reverses the characters in each element of the array.
You could define a function like this:
def slice_string_from_end(s)
s.reverse.scan(/.{1,3}/).each { |x| x.reverse! }
end
Then you can use:
slice_string_from_end("ABCDEFGH")
You can accomplish this using each_slice, but you'll need to reverse the string first, and then re-reverse each individual slice:
x = "ABCDEFGH"
x.chars.reverse.each_slice(3).map(&:reverse).map(&:join)
=> ["FGH", "CDE", "AB"]
split the string into a character array (x.chars)
reverse the array (.reverse)
slice the array into sub-arrays of 3 characters (.each_slice(3))
reverse each sub-array (.map(&:reverse))
join each sub-array back into a string (.map(&:join))
"ABCDEFGH".scan(/.+?(?=(?:.{3})*\z)/) # => ["AB", "CDE", "FGH"]
"ABCDEFGH".scan(/.+?(?=(?:.{3})*\z)/).reverse # => ["FGH", "CDE", "AB"]
split and scan also work, but like #meagar points out, you need to reverse and then re-reverse the string:
"ABCDEFGH".reverse.split(/(...)/).reject(&:empty?).map(&:reverse)
# => ["FGH", "CDE", "AB"]
the scan one doesn't need to look for empty strings:
"ABCDEFGH".reverse.scan(/...?/).map(&:reverse)
# => ["FGH", "CDE", "AB"]
You could use a while loop with some slice arithmetic:
s="ABCDEFGH"
li=[]
step=3
while s.length>0
ss=s[-(step<s.length ? step : s.length)..-1]
li << ss
s.chomp!(ss)
end
Same method works with a dynamic regex:
s="ABCDEFGH"
li=[]
step=3
reg=".{1,#{step}}$"
while s.length>0
ss=s[/#{reg}/]
li << ss
s.delete_suffix!(ss)
end
Either case:
> li
=> ["FGH", "CDE", "AB"]

Ruby how to return an element of a dictionary?

# dictionary = {"cat"=>"Sam"}
This a return a key
#dictionary.key(x)
This returns a value
#dictionary[x]
How do I return the entire element
"cat"=>"Sam"
#dictionary
should do the trick for you
whatever is the last evaluated expression in ruby is the return value of a method.
If you want to return the hash as a whole. the last line of the method should look like the line I have written above
Your example is a bit (?) misleading in a sense it only has one pair (while not necessarily), and you want to get one pair. What you call a "dictionary" is actually a hashmap (called a hash among Rubyists).
A hashrocket (=>) is a part of hash definition syntax. It can't be used outside it. That is, you can't get just one pair without constructing a new hash. So, a new such pair would look as: { key => value }.
So in order to do that, you'll need a key and a value in context of your code somewhere. And you've specified ways to get both if you have one. If you only have a value, then:
{ #dictionary.key(x) => x }
...and if just a key, then:
{ x => #dictionary[x] }
...but there is no practical need for this. If you want to process each pair in a hash, use an iterator to feed each pair into some code as an argument list:
#dictionary.each do |key, value|
# do stuff with key and value
end
This way a block of code will get each pair in a hash once.
If you want to get not a hash, but pairs of elements it's constructed of, you can convert your hash to an array:
#dictionary.to_a
# => [["cat", "Sam"]]
# Note the double braces! And see below.
# Let's say we have this:
#dictionary2 = { 1 => 2, 3 => 4}
#dictionary2[1]
# => 2
#dictionary2.to_a
# => [[1, 2], [3, 4]]
# Now double braces make sense, huh?
It returns an array of pairs (which are arrays as well) of all elements (keys and values) that your hashmap contains.
If you wish to return one element of a hash h, you will need to specify the key to identify the element. As the value for key k is h[k], the key-value pair, expressed as an array, is [k, h[k]]. If you wish to make that a hash with a single element, use Hash[[[k, h[k]]]].
For example, if
h = { "cat"=>"Sam", "dog"=>"Diva" }
and you only wanted to the element with key "cat", that would be
["cat", h["cat"]] #=> ["cat", "Sam"]
or
Hash[[["cat", h["cat"]]]] #=> {"cat"=>"Sam"}
With Ruby 2.1 you could alternatively get the hash like this:
[["cat", h["cat"]]].to_h #=> {"cat"=>"Sam"}
Let's look at a little more interesting case. Suppose you have an array arr containing some or all of the keys of a hash h. Then you can get all the key-value pairs for those keys by using the methods Enumerable#zip and Hash#values_at:
arr.zip(arr.values_at(*arr))
Suppose, for example,
h = { "cat"=>"Sam", "dog"=>"Diva", "pig"=>"Petunia", "owl"=>"Einstein" }
and
arr = ["dog", "owl"]
Then:
arr.zip(h.values_at(*arr))
#=> [["dog", "Diva"], ["owl", "Einstein"]]
In steps:
a = h.values_at(*arr)
#=> h.values_at(*["dog", "owl"])
#=> h.values_at("dog", "owl")
#=> ["Diva", "Einstein"]
arr.zip(a)
#=> [["dog", "Diva"], ["owl", "Einstein"]]
To instead express as a hash:
Hash[arr.zip(h.values_at(*arr))]
#=> {"dog"=>"Diva", "owl"=>"Einstein"}
You can get the key and value in one go - resulting in an array:
#h = {"cat"=>"Sam", "dog"=>"Phil"}
key, value = p h.assoc("cat") # => ["cat", "Sam"]
Use rassoc to search by value ( .rassoc("Sam") )

Search hash values for substring and return key in Ruby

I have an array:
array = ["One is enough", "Two is a couple", "Where's the beef?", "One"]
I then have a hash:
hash = {"one" => "Defined",
"two" => "Test"
}
I need to loop over each object in array and see if that object contains a substring that is found in the hash keys. If it is found, it should return the hash value. Otherwise, it should return undefined. The end goal is to create an array that looks like this:
final_array = ["Defined,"Test","Undefined","Defined"]
How can I write that loop effectively?
Here is an approach :
array = ["One is enough", "Two is a couple", "Where's the beef?", "One"]
hash = {"one" => "Defined","two" => "Test"}
array.map{|e| hash.find(proc{["undefined"]}){|k,v| e.downcase.include? k}.last}
# => ["Defined", "Test", "undefined", "Defined"]
Explanation:
Enumerable#find will be good idea. As doc is saying - Passes each entry in enum to block. Returns the first for which block is not false. If no object matches, calls ifnone and returns its result when it is specified, or returns nil otherwise.
I used Array#map,and passing each element string,to the block. Now inside the block I called #find on hash. Now hash.find passing each key/value pair to the hash.find method block. Inside that block I am calling String#include? method on e,passing key as argument to the #include? method. If #include? test results true,then key/value of that iteration is returned,otherwise default argument proc{["undefined"]}.call is being performed.
Hope that helps!
hash = {"one" => "Defined", "two" => "Test"}
array = ["One is enough", "Two is a couple", "Where's the beef?", "One"]
hash.default = "Undefined"
keys = hash.keys
array.map {|a| hash[(a.split.map(&:downcase) & keys).first]}
if hash does not contain a key 'k', hash[k] => "Undefined"
a.split.map(&:downcase) changes, for example, a = "One is Enough" to "one is enough"
the intersection with keys equals ["one"], ["two"], [nil], ["one"], respectively
.first is to extract the hash key from the 1-element arrays
the hash is evaluated at the computed hash key, with hash[nil] => "Undefined" (default)

Can someone explain why this ruby code for finding anagrams works?

Here's the line:
words.group_by { |word| word.downcase.chars.sort }.values
words is an array of words that are then sorted into groups if they share the same letters as another word in the original array. Can someone go down the line and explain how this works?
Okay, let's go through the methods one by one:
group_by: is a method that takes an Enumerable (in this case an Array) and a block. It passes each value in the array to the block, and then looks at the block's results. It then returns a Hash, where the keys are the results of the block, and the values are arrays of the original input that had the same result.
downcase: takes a string and makes it all lowercase
chars: converts a string into an array of characters
sort: sorts a collection
values: returns just the values of a Hash.
With those definitions, let's return to your code:
words.group_by { |word| word.downcase.chars.sort }.values
"Take each word in the array of words, make it lowercase, then sort its
letters into alphabetical order. The words that contain exactly the same
letters will have the same sorted result, so we can group them into a
Hash of Arrays, with the sorted letters as the key and the Array of
matching words as the value. We don't actually care what the actual letters
are, just the words that share them, so we take only the Arrays (the values)."
To break it down with an example:
words = %w[throw worth threw Live evil]
# => [ 'throw', 'worth', 'threw', 'Live', 'evil' ]
words_hash = words.group_by {|word| word.downcase.chars.sort}
# => {
# 'eilv' => [ 'evil', 'Live' ],
# 'ehrtw' => [ 'threw'],
# 'hortw' => [ 'throw', 'worth']
# }
words_hash.values
# => [['evil', 'Live'], ['threw'], ['throw', 'worth']]

Find difference between arrays in Ruby, where the elements are hashes

I have two arrays of hashes I would like to find the difference between. My issue is the array elements are single item hashes.
So far, using array1 - array2 appears to be working correctly but do I need to watch out for gotchas here? The hash elements themselves read like h = {'ID' => '76322'}, where the numeric value differs from hash to hash, so nothing too fancy.
[EDIT]
Here's what I'm looking for:
array1 = []
array2 = []
h = {'ID' => '76322'}
array1.push(h)
h = {'ID' => '7891'}
array1.push(h)
array2.push(h)
array1 = array1 - array2 # should result in array1 having a single hash of values {'ID', '76322'}
array1 - array2 works by putting the elements of array2 into a temporary hash, then returning all elements of array1 that don't appear in the hash. Hash elements are compared using == to determine whether they match.
Comparing two hashes with == gives true if all the keys and values of the hashes match using ==. So
h1 = {'ID' => '7891'}
h2 = {'ID' => '7891'}
h1 == h2
evaluates to true, even though h1 and h2 are different hashes, and the corresponding elements will be correctly removed.
The only consideration I can think of is if you always have strings everywhere in the hash keys and values. If they are sometimes integers, or symbols, like {:ID => 7891} then you aren't going to get the results you want, because :ID == 'ID' and '7891' == 7891 are both false.

Resources