1

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?

4
  • Luigi, if future, I suggest you wait a bit longer before selecting an answer. Once you have done so, some readers will just move on to the next question. This time you had the good fortune of getting a nice "late" answer from @sawa, but that will not always be the case. (I also offered a "late" answer, but only because it was a bit different, not because I thought it was the best one.) Commented Oct 12, 2013 at 5:10
  • @CarySwoveland I've been promoting explanations via my answer and moderation here. This site has great answers on most 'language primitive' topics, already (except for new languages; D, rust, &c. Thus, what's needed next is clear, concise explanations. In some regards it would have been hard to give a transparent answer if I abbreviated my answer as much as Sawa, though I probably would have tried in another context. Commented Oct 12, 2013 at 15:04
  • @NewAlexandria, I agree with you, and often do that (and sometimes get a little carried away), but I could do better. My main point, though, was that a quick-draw checkmark does not encourage other--sometimes better and/or diverse--answers. Commented Oct 12, 2013 at 16:20
  • I agree @CarySwoveland. I am new to programming in general and especially Ruby, and I have learned 95% of what I know this far from the answers on this site. The diversity in the answers is great when coupled with an explanation as I can not only learn new methods and ways of doing things but I also learn some of the why behind which methods are better. Right now the majority of my scripts are time insensitive, but in the future security risks and time sensitivity will be a huge factor in my programming, and those are the things I learn here from the many answer. Thanks for the answer and tip. Commented Oct 12, 2013 at 16:26

5 Answers 5

2
first_array.map{|s| s[/\d+/].to_i}
# => [8, 7] 
Sign up to request clarification or add additional context in comments.

Comments

1
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

Comments

1

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]

Comments

1

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]

2 Comments

So much over engineering for this, but maybe great if reaching exiting is appropriate
It's simply that I am trying to show 2 unrelated things at the same time: 1. that the OP's array envies being a Hash, and 2. usage of Pyper to write shorter code. (But with Pyper, shorter ≠ more readable, same as with APL language :-)))
0

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"} 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.