Prefer %W(...) to a Literal Array

Prefer %w(...) to a literal array?

Voila!, one benchmark:

require 'benchmark'

n = 1_000_000
Benchmark.bm(11) do |b|
b.report('%w') { n.times { %w[a b c d e f g h i j k l m n o p q r s t u v w x y z] } }
b.report('explicit') { n.times { ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm', 'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z'] } }
b.report('numerics') { n.times { [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26] } }
end

user system total real
%w 2.590000 0.000000 2.590000 ( 2.591225)
explicit 2.590000 0.000000 2.590000 ( 2.584781)
numerics 0.300000 0.000000 0.300000 ( 0.309161)

user system total real
%w 2.590000 0.000000 2.590000 ( 2.591516)
explicit 2.590000 0.000000 2.590000 ( 2.584155)
numerics 0.300000 0.000000 0.300000 ( 0.308896)

user system total real
%w 2.590000 0.000000 2.590000 ( 2.592848)
explicit 2.590000 0.000000 2.590000 ( 2.585558)
numerics 0.300000 0.000000 0.300000 ( 0.308570)

I added the "numerics" array test because I suspected that %w is faster than using explicit strings due to testing for stringiness. %w doesn't need to do that, because it assumes everything is a string. After running it three times it's a wash as far as dealing with strings. Numbers rule, strings drool, and all that.


The previous benchmarks were run using Ruby 1.9.3-p286 on my system at work. I tested again using my old MacBook Pro at home, using Ruby 1.8.7-p358, so the following numbers are slower due to the differences in the hosting hardware, plus running an older Ruby:

                user     system      total        real
%w 3.070000 0.000000 3.070000 ( 3.080983)
explicit 3.100000 0.000000 3.100000 ( 3.093083)
numerics 0.950000 0.040000 0.990000 ( 0.990535)

user system total real
%w 3.080000 0.010000 3.090000 ( 3.076787)
explicit 3.090000 0.000000 3.090000 ( 3.089246)
numerics 0.950000 0.030000 0.980000 ( 0.989579)

user system total real
%w 3.080000 0.000000 3.080000 ( 3.073877)
explicit 3.090000 0.000000 3.090000 ( 3.091576)
numerics 0.950000 0.030000 0.980000 ( 0.989132)

On 1.8.7, %w was a tiny bit faster consistently, which probably gave rise to the speed-rumors.

What does %w(array) mean?

%w(foo bar) is a shortcut for ["foo", "bar"]. Meaning it's a notation to write an array of strings separated by spaces instead of commas and without quotes around them. You can find a list of ways of writing literals in zenspider's quickref.

Why favor the use of %w over ['foo', 'bar']

For three reasons:

  1. %w is more idiomatic ruby

When reading ruby code you will come across %w a lot when dealing with an array of strings. While you can write a simple [] and achieve the same thing %w is the 'ruby way'.


  1. %w conveys more meaning than []

The second and I think more important reason is %w conveys a more specific meaning. An array created with %w can only hold strings, it cannot for example hold integers. So the code is showing its intent clearer to the programmer by pointing out that this array will only ever have strings.


  1. The Ruby philosophy: Multiple ways to do one thing.

Ruby has a philosophy (rightly or wrongly) that the language should give the programmer multiple options to do the same thing so they can do what they think is right. So if you disagree with the rule thats ok :) Here is an snippet from an interview with the creator of Ruby Yukihiro Matsumoto

Ruby inherited the Perl philosophy of having more than one way to do the same thing. I inherited that philosophy from Larry Wall, who is my hero actually. I want to make Ruby users free. I want to give them the freedom to choose. People are different. People choose different criteria. But if there is a better way among many alternatives, I want to encourage that way by making it comfortable. So that's what I've tried to do. Maybe Python code is a bit more readable. Everyone can write the same style of Python code, so it can be easier to read, maybe. But the difference from one person to the next is so big, providing only one way is little help even if you're using Python, I think. I'd rather provide many ways if it's possible, but encourage or guide users to choose a better way if it's possible. - Yukihiro Matsumoto 2003 http://www.artima.com/intv/rubyP.html

How to modify elements of Ruby Array composed of Frozen String Literals

Frozen objects can't be unfrozen. But you can build new objects from them.

# frozen_string_literal: true

alphabet = %w(a b c)
alphabet = alphabet.map do |letter|
letter + 'suffix'
end

How to initialize an array in one step using Ruby?

You can use an array literal:

array = [ '1', '2', '3' ]

You can also use a range:

array = ('1'..'3').to_a  # parentheses are required
# or
array = *('1'..'3') # parentheses not required, but included for clarity

For arrays of whitespace-delimited strings, you can use Percent String syntax:

array = %w[ 1 2 3 ]

You can also pass a block to Array.new to determine what the value for each entry will be:

array = Array.new(3) { |i| (i+1).to_s }

Finally, although it doesn't produce the same array of three strings as the other answers above, note also that you can use enumerators in Ruby 1.8.7+ to create arrays; for example:

array = 1.step(17,3).to_a
#=> [1, 4, 7, 10, 13, 16]

Create array of symbols

The original answer was written back in September '11, but, starting from Ruby 2.0, there is a shorter way to create an array of symbols! This literal:

%i[address city state postal country]

will do exactly what you want.

Ruby Array Issue - can't convert String into Integer

As juanpastas mentions, Array::new(size,obj) expects a number and an object. You can see this in the tutorial you linked to:

names = Array.new(4, "mac")

names is now an array with "mac" four times.

If your intention is to create an array with these two items:

pullTags = Array.[nameTag, designsTag]
# which is equivalent to
pullTags = Array[nameTag, designsTag]
# which are the more verbose versions of
pullTags = [nameTag, designsTag]

See [](*args).

Omission of curly braces for a hash in an array

This would seem to be a new feature of 1.9:

$ rvm use 1.8.7
$ irb
ruby-1.8.7-p352 :001 > x = [ 1,2,3,:a => 4, :b => 5 ]
SyntaxError: compile error
(irb):1: syntax error, unexpected tASSOC, expecting ']'
x = [ 1,2,3,:a => 4, :b => 5 ]
^
from (irb):1
ruby-1.8.7-p352 :002 > exit
$ rvm use 1.9.3
$ irb
ruby-1.9.3-p0 :001 > x = [ 1,2,3,:a => 4, :b => 5 ]
=> [1, 2, 3, {:a=>4, :b=>5}]
ruby-1.9.3-p0 :002 >


Related Topics



Leave a reply



Submit