I currently have this written up for turning my string elements into a hash[key] with its indices as values
def char_indices(str)
array = str.split(//)
hash = array.each_with_object({}).with_index {|(el, h), i| h[el] = []<<i}
p hash
end
which returns
{"m"=>[0], "i"=>[10], "s"=>[6], "p"=>[9]}
{"c"=>[0], "l"=>[1], "a"=>[2], "s"=>[4], "r"=>[5], "o"=>[7], "m"=>[8]}
but I need
char_indices('mississippi') # => {"m"=>[0], "i"=>[1, 4, 7, 10], "s"=>[2, 3, 5, 6], "p"=>[8, 9]}
char_indices('classroom') # => {"c"=>[0], "l"=>[1], "a"=>[2], "s"=>[3, 4], "r"=>[5], "o"=>[6, 7], "m"=>[8]}
problem is my value is getting replaced each time and i only end up with the last value.
how can i add each recurring location to value in a ruby like fashion.
CodePudding user response:
The problem is h[el] = []<<i
. Instead you can use conditional assignment to ensure that you're working with an array:
def char_indices(string)
string.each_char
.with_index
.with_object({}) do |(char, index), hash|
hash[char] ||= []
hash[char] << index
end
end
CodePudding user response:
def char_indices(str)
str.each_char.
with_index.
with_object({}) do |(c,i),h|
(h[c] ||= []) << i
end
end
char_indices('mississippi')
#=> {"m"=>[0], "i"=>[1, 4, 7, 10], "s"=>[2, 3, 5, 6], "p"=>[8, 9]}
char_indices('classroom')
#=> {"c"=>[0], "l"=>[1], "a"=>[2], "s"=>[3, 4], "r"=>[5], "o"=>
[6, 7], "m"=>[8]}
Notice how I've written the block variables: |(c,i),h|
. This makes use of Ruby's array decomposition rules. See also this article on the subject.
The method is equivalent to the following.
def char_indices(str)
h = {}
str.each_char.
with_index do |c,i|
h[c] = [] unless h.key?(c)
h[c] << i
end
h
end
One could alternatively write the method like this:
def char_indices(str)
str.each_char.
with_index.
with_object(Hash.new { |h,k| h[k] = [] }) { |(c,i),h| h[c] << i }
end
This uses the form of Hash::new that takes a block and no argument. If
h = Hash.new { |h,k| h[k] = [] }
than, possibly after keys have been added, if h.key?(k) #=> false
, h[k] = []
is executed. Here, when
h[c] << i
is encountered, if h.key?(c) #=> false
, h[c] = []
is executed, after which h[c] << i
is executed, resulting in h[c] #=> [c]
.