2

I have an array [1, 2, "3", "4", "1a", "abc", "a"] with

  • pure integers (1, 2),
  • string formatted integers ("1", "2"),
  • strings ("a", "b"), and
  • mixed string numbers ("1a", "2s").

From this, I need to pick up only the integers (including string formatted) 1, 2, "3", "4".

First I tried with to_i:

arr = [1, 2, "3", "4", "1a", "abc", "a"]
arr.map {|x| x.to_i}
# => [1, 2, 3, 4, 1, 0, 0]

but this one converts "1a" to 1, which I don't expect.

Then I tried Integer(item):

arr.map {|x| Integer(x) }  # and it turned out to be
# => ArgumentError: invalid value for Integer(): "1a"

Now I am out of straight conversion options here. Finally, I decided to do this way, which converts the value to_i and to_s. So "1" == "1".to_i.to_s is an integer, but not "1a" == "1a".to_i.to_s and "a" == "a".to_i.to_s

arr  = arr.map do |x|
  if (x == x.to_i.to_s)
    x.to_i
  else
    x
  end
end

and

ids, names= arr.partition { |item| item.kind_of? Fixnum }

Now I got the arrays of integers and strings. Is there a simple way to do this?

4
  • -1. You write that your array includes string formatted integers "1", "2", but they are not in your array. Also, string "b" and mixed string numbers "2s" are not found. Commented Apr 24, 2011 at 17:08
  • do you need to return it as integers or as original type. I meen do you need to get [1,2,3,4] or [1,2,"3","4"] ? Commented Apr 24, 2011 at 17:34
  • @sawa, its a typo sawa... i meant to type "3","4". what difference it makes to say string formatted numbers. its a example i wanted to convey... Commented Apr 25, 2011 at 7:05
  • If the explanations and the examples contradict, how is it possible to know your intention? If the question is difficult to understand or does not make sense, then it is not a good question. Commented Apr 25, 2011 at 7:11

7 Answers 7

7

Similar solution as provided by @maerics, but a bit slimmer:

arr.map {|x| Integer(x) rescue nil }.compact
Sign up to request clarification or add additional context in comments.

2 Comments

I wanted to post almost the same, but using select like this: >> a.select { |i| Integer(i) rescue false } #=> [1, 2, "3", "4"]. Anyway, since the solution is so similar, I'll let you have this one. :-)
I would say this idiom is more pythonist than rubyist "Ask forgiveness not permission". In Ruby though, to rescue an exception might be expensive in terms of performance, see this benchmark: technicaldebt.com/the-cost-of-using-rubys-rescue-as-logic
3
class Array
  def to_i
    self.map {|x| begin; Integer(x); rescue; nil; end}.compact
  end
end

arr = [1, 2, "3", "4", "1a", "abc", "a"]
arr.to_i # => [1, 2, 3, 4]

Comments

2

something like this:

a = [1,2,"3","4","1a","abc","a"]



irb(main):005:0> a.find_all { |e| e.to_s =~ /^\d+$/ }.map(&:to_i)
=> [1, 2, 3, 4]

1 Comment

I would put the to_i inside the find_all block. This prevent the double iteration.
2

Hey, thanks awakening my ruby. Here is my go at this problem:

arr=[1,2,"3","4","1a","abc","a"]
arr.map {|i| i.to_s}.select {|s| s =~ /^[0-9]+$/}.map {|i| i.to_i}
//=> [1, 2, 3, 4]

Comments

1

I noticed most of the answer so far changes the value of "3" and "4" to actual integers.

>> array=[1, 2, "3", "4", "1a", "abc", "a", "a13344a" , 10001, 3321]
=> [1, 2, "3", "4", "1a", "abc", "a", "a13344a", 10001, 3321]
>> array.reject{|x| x.to_s[/[^0-9]/] }
=> [1, 2, "3", "4", 10001, 3321]

@OP, I have not tested my solution exhaustively, but so far it seems to work (of course its done according to provided sample ), so please test thoroughly yourself.

Comments

1

How about this?

[1,2,"3","4","1a","abc","a"].select{|x| x.to_i.to_s == x.to_s}
# => [1, 2, "3", "4"]

Comments

0

Looks pretty simple

arr.select{ |b| b.to_s =~ /\d+$/ }
# or
arr.select{ |b| b.to_s[/\d+$/] }
#=> [1, 2, "3", "4"]

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.