Check value in loop - ruby

I'm iterating through an array:
#fileArray.each() {
|x|
}
How can I access the value x to check if it begins with a specific string?

test = ['abc', 'bcef', 'abcdef']
p test.select{|word| word.start_with?('abc')}
#=> ["abc", "abcdef"]
# or the very short:
test.grep(/^abc/)
#=> ["abc", "abcdef"]

This seems to do the trick!
test = ['abc', 'bcabcef', 'abcdef']
test.each do |x|
if x.match(/^abc/)
puts x
end
end
Outputs:
abc
abcdef

You could use select.
["a","ab","b","ac","c"].select{|x| x[0] == "a"}
=> ["a", "ab", "ac"]
If not, then you can just do
x[0..5] == "String"

Related

How to check if a key exists in an array of arrays?

Is there a straightforward way to do something like the following without excessive looping?
myArray = [["a","b"],["c","d"],["e","f"]]
if myArray.includes?("c")
...
I know this works fine if it's just a normal array of chars... but I would like something equally as elegant for an array of an array of chars (bonus points for helping convert this to an array of tuples).
If you only need a true/false answer you can flatten the array and call include on that:
>> myArray.flatten.include?("c")
=> true
You can use assoc:
my_array = [['a', 'b'], ['c', 'd'], ['e', 'f']]
if my_array.assoc('c')
# ...
It actually returns the whole subarray:
my_array.assoc('c') #=> ["c", "d"]
or nil if there is no match:
my_array.assoc('g') #=> nil
There's also rassoc to search for the second element:
my_array.rassoc('d') #=> ["c", "d"]
my_array = [["a","b"],["c","d"],["e","f"]]
p my_hash = my_array.to_h # => {"a"=>"b", "c"=>"d", "e"=>"f"}
p my_hash.key?("c") # => true
You can use Array#any?
myArray = [["a","b"],["c","d"],["e","f"]]
if myArray.any? { |x| x.includes?("c") }
# some code here
The find_index method works well for this:
myArray = [["a","b"],["c","d"],["e","f"]]
puts "found!" if myArray.find_index {|a| a[0] == "c" }
The return value is the array index of the pair or nil if the pair is not found.
You can capture the pair's value (or nil if not found) this way:
myArray.find_index {|a| a[0] == "c" } || [nil, nil])[1]
# => "d"

Counting unique occurrences of values in a hash

I'm trying to count occurrences of unique values matching a regex pattern in a hash.
If there's three different values, multiple times, I want to know how much each value occurs.
This is the code I've developed to achieve that so far:
def trim(results)
open = []
results.map { |k, v| v }.each { |n| open << n.to_s.scan(/^closed/) }
puts open.size
end
For some reason, it returns the length of all the values, not just the ones I tried a match on. I've also tried using results.each_value, to no avail.
Another way:
hash = {a: 'foo', b: 'bar', c: 'baz', d: 'foo'}
hash.each_with_object(Hash.new(0)) {|(k,v),h| h[v]+=1 if v.start_with?('foo')}
#=> {"foo"=>2}
or
hash.each_with_object(Hash.new(0)) {|(k,v),h| h[v]+=1 if v =~ /^foo|bar/}
#=> {"foo"=>2, "bar"=>1}
Something like this?
hash = {a: 'foo', b: 'bar', c: 'baz', d: 'foo'}
groups = hash.group_by{ |k, v| v[/(?:foo|bar)/] }
# => {"foo"=>[[:a, "foo"], [:d, "foo"]],
# "bar"=>[[:b, "bar"]],
# nil=>[[:c, "baz"]]}
Notice that there is a nil key, which means the regex didn't match anything. We can get rid of it because we (probably) don't care. Or maybe you do care, in which case, don't get rid of it.
groups.delete(nil)
This counts the number of matching "hits":
groups.map{ |k, v| [k, v.size] }
# => [["foo", 2], ["bar", 1]]
group_by is a magical method and well worthy of learning.
def count(hash, pattern)
hash.each_with_object({}) do |(k, v), counts|
counts[k] = v.count{|s| s.to_s =~ pattern}
end
end
h = { a: ['open', 'closed'], b: ['closed'] }
count(h, /^closed/)
=> {:a=>1, :b=>1}
Does that work for you?
I think it worths to update for RUBY_VERSION #=> "2.7.0" which introduces Enumerable#tally:
h = {a: 'foo', b: 'bar', c: 'baz', d: 'foo'}
h.values.tally #=> {"foo"=>2, "bar"=>1, "baz"=>1}
h.values.tally.select{ |k, _| k=~ /^foo|bar/ } #=> {"foo"=>2, "bar"=>1}

How do I create a hash from this array?

I have an array that looks like this:
["value1=3", "value2=4", "value3=5"]
I'd like to end up with a hash like:
H['value1'] = 3
H['value2'] = 4
H['value3'] = 5
There's some parsing involved and I was hoping to get pointed in the right direction.
ary = ["value1=3", "value2=4", "value3=5"]
H = Hash[ary.map {|s| s.split('=') }]
This however will set all the values as strings '5' instead of integer. If you are sure they are all integers:
H = Hash[ary.map {|s| key, value = s.split('='); [key, value.to_i] }]
I'd do as #BroiSatse suggests, but here's another way that uses a Regex:
ary = ["value1=3", "value2=4", "value3=5"]
ary.join.scan(/([a-z]+\d+)=(\d+)/).map { |k,v| [k,v.to_i] }.to_h
=> {"value1"=>3, "value2"=>4, "value3"=>5}
Here's what's happening:
str = ary.join
#=> "value1=3value2=4value3=5"
a = str.scan(/([a-z]+\d+)=(\d+)/)
#=> [["value1", "3"], ["value2", "4"], ["value3", "5"]]
b = a.map { |k,v| [k,v.to_i] }
#=> [["value1", 3], ["value2", 4], ["value3", 5]]
b.to_h
#=> {"value1"=>3, "value2"=>4, "value3"=>5}
For Ruby versions < 2.0, the last line must be replaced with
Hash[b]
#=> {"value1"=>3, "value2"=>4, "value3"=>5}

How do you replace a string with a hash collection value in Ruby?

I have a hash collection:
my_hash = {"1" => "apple", "2" => "bee", "3" => "cat"}
What syntax would I use to replace the first occurrence of the key with hash collection value in a string?
eg my input string:
str = I want a 3
The resulting string would be:
str = I want a cat
My one liner:
hash.each { |k, v| str[k] &&= v }
or using String#sub! method:
hash.each { |k, v| str.sub!(k, v) }
"I want a %{b}" % {c: "apple", b: "bee", a: "cat"}
=> "I want a bee"
Assuming Ruby 1.9 or later:
str.gsub /\d/, my_hash
I didn't understand your problem, but you can try this:
my_hash = {"1" => "apple", "2" => "bee", "3" => "cat"}
str = "I want a 3"
str.gsub(/[[:word:]]+/).each do |word|
my_hash[word] || word
end
#=> "I want a cat"
:D
Just to add point free style abuse to fl00r's answer:
my_hash = {"1" => "apple", "2" => "bee", "3" => "cat"}
my_hash.default_proc = Proc.new {|hash, key| key}
str = "I want a 3"
str.gsub(/[[:word:]]+/).each(&my_hash.method(:[]))
my_hash = {"1" => "apple", "2" => "bee", "3" => "cat"}
str = "I want a 3"
If there isn't any general pattern for the strings you want to substitute, you can use:
str.sub /#{my_hash.keys.map { |s| Regexp.escape s }.join '|'}/, my_hash
But if there is one, the code becomes much simpler, e.g.:
str.sub /[0-9]+/, my_hash
If you want to substitute all the occurrences, not only the first one, use gsub.
You can use String.sub in ruby 1.9:
string.sub(key, hash[key])
The following code replace the first occurrence of the key with hash collection value in the given string str
str.gsub(/\w+/) { |m| my_hash.fetch(m,m)}
=> "I want a cat"

Ruby array to hash: each element the key and derive value from it

I have an array of strings, and want to make a hash out of it. Each element of the array will be the key, and I want to make the value being computed from that key. Is there a Ruby way of doing this?
For example:
['a','b'] to convert to {'a'=>'A','b'=>'B'}
You can:
a = ['a', 'b']
Hash[a.map {|v| [v,v.upcase]}]
%w{a b c}.reduce({}){|a,v| a[v] = v.upcase; a}
Ruby's each_with_object method is a neat way of doing what you want
['a', 'b'].each_with_object({}) { |k, h| h[k] = k.upcase }
Here's another way:
a.zip(a.map(&:upcase)).to_h
#=>{"a"=>"A", "b"=>"B"}
Which ever way you look at it you will need to iterate the initial array. Here's another way :
a = ['a', 'b', 'c']
h = Hash[a.collect {|v| [v, v.upcase]}]
#=> {"a"=>"A", "b"=>"B", "c"=>"C"}
Here's a naive and simple solution that converts the current character to a symbol to be used as the key. And just for fun it capitalizes the value. :)
h = Hash.new
['a', 'b'].each {|a| h[a.to_sym] = a.upcase}
puts h
# => {:a=>"A", :b=>"B"}
From Rails 6.x, you can use Enumerable#index_with:
irb(main):002:0> ['a', 'b'].index_with {|s| s.upcase}
=> {"a"=>"A", "b"=>"B"}
Pass a block to .to_h
[ 'a', 'b' ].to_h{ |element| [ element, element.upcase ] }
#=> {"a"=>"A", "b"=>"B"}
Thanks to #SMAG for the refactor suggestion!
Not sure if this is the real Ruby way but should be close enough:
hash = {}
['a', 'b'].each do |x|
hash[x] = x.upcase
end
p hash # prints {"a"=>"A", "b"=>"B"}
As a function we would have this:
def theFunk(array)
hash = {}
array.each do |x|
hash[x] = x.upcase
end
hash
end
p theFunk ['a', 'b', 'c'] # prints {"a"=>"A", "b"=>"B", "c"=>"C"}

Resources