Reputation: 467
I want to convert the elements of the string array below to symbols, and output them
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
look at what I'm doing:
strings.each { |x| puts x.to_sym }
No success. What am I doing wrong?
Upvotes: 43
Views: 45170
Reputation: 399
In the interest of completeness you can also make use of the %i
string literal since at least Ruby 2.0.0 to start off with an array of symbols.
%i[HTML CSS JavaScript Python Ruby]
# => [:HTML, :CSS, :JavaScript, :Python, :Ruby]
Upvotes: 0
Reputation: 3176
If you want to go the gem route, finishing_moves has an Array#to_sym_strict
method that does exactly what you're looking for:
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
strings.to_sym_strict
# => [:HTML, :CSS, :JavaScript, :Python, :Ruby]
There's also a #to_sym_loose
to handle arrays of mixed type:
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby", 1, /a regex/, {a: :hash}]
strings.to_sym_loose
# => [:HTML, :CSS, :JavaScript, :Python, :Ruby, 1, /a regex/, {a: :hash}]
# no exceptions thrown
Upvotes: 1
Reputation: 1252
@cb24's answer is generally the most appropiate, I wanted to compare that solution with another one
strings.collect {|x| x.to_sym }
I did some benchmarks and @cb24's answer works best in most cases, when there are some more elements in the array, but if it happens to be a very tiny array, the collect method works a little faster.
I publish here the code and the results, this is my real first benchmark so if I got something wrong some feedback would be appreciated. I did it on both String -> Symbol and Symbol -> String
n = 1000000
a = [:a,:b,:c,:d,:e,:f,:g,:h,:i].freeze #A "long" array of symbols
Benchmark.bm do |x|
x.report { n.times { a.map(&:to_s)} }
x.report { n.times { a.collect{|x| x.to_s}} }
end
user system total real
2.040000 0.010000 2.050000 ( 2.056784)
2.100000 0.010000 2.110000 ( 2.118546)
b = [:a, :b].freeze #Small array
Benchmark.bm do |x|
x.report { n.times { b.map(&:to_s)} }
x.report { n.times { b.collect{|x| x.to_s}} }
end
user system total real
0.610000 0.000000 0.610000 ( 0.622231)
0.530000 0.010000 0.540000 ( 0.536087)
w = %w(a b).freeze #Again, a small array, now of Strings
Benchmark.bm do |x|
x.report { n.times { w.map(&:to_sym)} }
x.report { n.times { w.collect{|x| x.to_sym}} }
end
user system total real
0.510000 0.000000 0.510000 ( 0.519337)
0.440000 0.010000 0.450000 ( 0.447990)
y = %w(a b c d e f g h i j k l m n o p q).freeze #And a pretty long one
Benchmark.bm do |x|
x.report { n.times { y.map(&:to_sym)} }
x.report { n.times { y.collect{|x| x.to_sym}} }
end
user system total real
2.870000 0.030000 2.900000 ( 2.928830)
3.240000 0.030000 3.270000 ( 3.371295)
The inflection points I didn't calculate but it is quite interesting, I read somewhere that some improvements where made with short arrays, since most of them are just a couple of elements long.
Upvotes: 2
Reputation: 18572
@icktoofay has the correct answer, but just to help you better understand the each
method, here is how you can do the same thing using each
:
strings = ["HTML", "CSS", "JavaScript", "Python", "Ruby"]
symbols = [] # an empty array to hold our symbols
strings.each { |s| symbols << s.to_sym }
Upvotes: 2
Reputation: 637
Clean one-liner:
%w(HTML CSS JavaScript Python Ruby).map(&:to_sym)
&
tells argument should be treated as a block, i.e. build up array and apply to_sym
to each element.
Upvotes: 37
Reputation: 11
Or can be done as follows:
strings.each do |s|
symbols.push(s.to_sym)
Upvotes: 0
Reputation: 27845
icktoofay already gave the correct answer.
On additional remark: With
strings.map { |x| x.to_sym }
you get a new array, the original array is unchanged.
To use it, you can assign it to another variable:
string2 = strings.map { |x| x.to_sym }
If you want to modify string, you can use map!
:
strings.map! { |x| x.to_sym }
Upvotes: 4
Reputation: 128991
Use map
rather than each
:
>> strings.map { |x| x.to_sym }
=> [:HTML, :CSS, :JavaScript, :Python, :Ruby]
For Ruby 1.8.7 and later or with ActiveSupport included, you can use this syntax:
>> strings.map &:to_sym
=> [:HTML, :CSS, :JavaScript, :Python, :Ruby]
The reason your each
method appears to not work is that calling puts
with a symbol outputs the string representation of the symbol (that is, without the :
). Additionally, you're just looping through and outputting things; you're not actually constructing a new array.
Upvotes: 60