Luigi
Luigi

Reputation: 5603

Only push specific substring to array in Ruby

I have an array that I am looping through and pushing specific values to a separate array. EX:

first_array = ["Promoter: 8", "Passive: 7"]

I want to push every value that is an integer to a separate array, that would look like this in the end:

final_array = [8,7]

It would be nice for the values in the new array to be integers. I can't think of a way to push all numeric values within a string to a new array, but what would be the best option to do what I am wanting?

Upvotes: 1

Views: 124

Answers (5)

Cary Swoveland
Cary Swoveland

Reputation: 110755

If the integer part of each string in (which look like members of a hash) is always preceded by at least one space, and there is no other whitespace (other than possibly at the beginning of the string), you could do this:

first_array = ["Promoter: 8", "Passive: 7"]
Hash[*first_array.map(&:split).flatten].values.map(&:to_i) # => [8,7]
  • map first_array => [["Promoter:", "8"], ["Passive:", "7"]]
  • flatten => ["Promoter:", "8", "Passive:", "7"]
  • convert to hash => {"Promoter:" => "8", "Passive:" => "7"}
  • get hash values => ["8", "7"]
  • convert to ints => [8, 7]

Note the need for the splat:

 Hash[*["Promoter:", "8", "Passive:", "7"]]
   => Hash["Promoter:", "8", "Passive:", "7"]                                               
   => {"Promoter:" => "8", "Passive:" => "7"} 

Upvotes: 0

Boris Stitnicky
Boris Stitnicky

Reputation: 12588

Your question, as formulated, has an easy practical answer, already provided by others. But it seems to me, that your array of strings

a = ["Promoter: 8", "Passive: 7"]

envies being a Hash. So, from broader perspective, I would take freedom of converting it to a Hash first:

require 'pyper' # (type "gem install pyper" in your command line to install it)
hsh = Hash[ a.τBmm2dτ &/(\w+): *(\d+)/.method( :match ) ]
#=> {"Promoter"=>"8", "Passive"=>"7"}
# (The construction of #τBmm2dτ Pyper method will be explained in the appendix.)

Now, having your input data in a hash, you can do things with them more easily, eg.

hsh.τmbtiτ
#=> [8, 7]

APPENDIX: Explanation of the Pyper methods.

Pyper methods are similar to Lisp #car/#cdr methods in that, that a combination of letters controls the method behavior. In the first method, #τBmm2dτ:

  • τ - opening and ending character
  • m - means #map
  • B - means take a block
  • 2 - means first 3 elements of an array
  • d - means all elements except the first one (same meaning as in #cdr, btw.)

So, in #τBmm2dτ, Bm applies the block as follows:

x = ["Promoter: 8", "Passive: 7"].map  &/(\w+): *(\d+)/.method( :match )
#=> [#<MatchData "Promoter: 8" 1:"Promoter" 2:"8">, #<MatchData "Passive: 7" 1:"Passive" 2:"7">]
# Which results in an array of 2 MatchData objects.

Then, m2d chars map (m) the MatchData objects using 2 and d chars. Character 2 gives

x = x.map { |e| e.to_a.take 3 }
#=> [["Promoter: 8", "Promoter", "8"], ["Passive: 7", "Passive", "7"]]

and d removes the first element from each:

x = x.map { |e| e.drop 1 }
#=> [["Promoter", "8"], ["Passive", "7"]]

In the secon method, #τmbtiτ, m means again #map, b means take the second element, and ti means convert it to Integer:

{"Promoter"=>"8", "Passive"=>"7"}.to_a.map { |e| Integer e[1] }
#=> [8, 7]

Upvotes: 1

hirolau
hirolau

Reputation: 13921

And I have to add this super short but complicated one-liner solution:

a = ["Promoter: 8", "Passive: 7"]
p a.grep(/(\d+)/){$&.to_i} #=> [8,7]

Upvotes: 1

sawa
sawa

Reputation: 168269

first_array.map{|s| s[/\d+/].to_i}
# => [8, 7] 

Upvotes: 2

New Alexandria
New Alexandria

Reputation: 7334

first_array.map{|a| a.match(/\d+/)}.compact.map{|a| a[0].to_i }
  • Use a regex to grab the integers,
  • compact the blank spaces from the strings with no integers, and
  • convert them all to ints

Upvotes: 1

Related Questions