a = ['one', 2, 3.0]
A quick way to create an array of strings (if each string is a single word) is like this (you can use any matching brackets, or indeed more punctuation):
a = %w(one two three)
# => ["One", "Two", "Three"]
To add an element to an existing array do this:
array << "new element"You can join two arrays using the addition operator.
b = [4, 16]
c = a + b
# => ["One", "Two", "Three", 4, 16]
Use
include?
to determine if the given object is in the array. To access an array member use []
, or at
or fetch
. The []
and at
methods return nil
if the index is out of range, while fetch
throws an exception, or a default value of given. A negative index counts back from the end, while a range returns a subset of the array.ary = %w(zero one two three four five six)
p ary[2]
# => "two"
p ary.at(3)
# => "three"
p ary[-1]
# => "six"
p ary[2..4]
# => ["two, "three", "four"]
delete_if
Ruby has some very neat tricks with arrays. Want to delete all the elements of an array of hashes that have a body that is nil?
array.delete_if { |x| x.body.nil? }
The
delete_if
removes from the array any elements that evaulate to true in the block. Note that the delete_if
method seems to ignore the convention of naming methods that affect the object itself with an exclamation mark.join
The
join
method concatenates each member of an array into a long string. The supplied parameter is used to separate each item. The * operator does the same.a = %w(one two three four)
# => ["one", "two", "three", "four"]
a * ', '
# => "one, two, three, four"
map, select and reject
The
map
method (aka collect
) constructs a new array by processing each element in the array as per the block, while select
returns a new array containing only those elements where the block evaluates to true. The reject
method gives an array for the elements where the block is not true.people = [
{:name => 'Fred', :age => 19},
{:name => 'Boris', :age => 23},
{:name => 'Mary', :age => 27},
]
p people.map {|e| e[:name]}
# => ["Fred", "Boris", "Mary"]
p people.select {|e| e[:age] <> [{:name=>"Fred", :age=>19}]
p people.reject {|e| e[:age] <> [{:name=>"Boris", :age=>23},
{:name=>"Mary", :age=>27}]
sort
The
sort
method will, as the name suggests, sort the array, using the <=>
relationship. Alternatively you can supply block to have it sorted by a custom comparison.people.sort { |a, b| a[:age] <=> b[:age] }
# youngest to oldest
Note that your comparison must return -1, 0, or +1. In this example, I therefore could not use <.
If you use the
Enumerable
mixin discussed later you also have a sort_by
method. This is not as fast to run, but can be quicker to code. In this method, the block determines a value for the element, for ranking purposes. Here is the previous example re-written.people.sort_by { |a| a[:age] }
pop and push, shift and unshift
You can use
push
and pop
to add or remove the last element, and unshift and shift
to add and remove from the start.
a = %w(one two three)
# => ["one", "two", "three"]
a.push 'four'
# => ["one", "two", "three", "four"]
a.pop
# => "four"
a
# => ["one", "two", "three"]
a.unshift 'zero'
# => ["zero", "one", "two", "three"]
a.shift
# => "zero"
a
# => ["one", "two", "three"]
Extending Array, part 1
You can, of course, add your own methods to Array. Here are some examples.
class Array
# Shuffle an array
# from http://snippets.dzone.com/posts/show/2994
def shuffle
sort_by { rand }
end
def shuffle!
self.replace shuffle
end
# Randomly pick one element of the array.
def pick
fetch rand(length)
end
# Returns a total over each element in the array
# where the value for an element is determined
# by the given block. This example will look
# through an array of hashes
# and return the total of the square of values
# with the key :value
# ary.total { |e| e[:value] * e[:value] }
def total &prc
val = 0
each do |e|
val += prc.call(e)
end
val
end
# Returns an element that best fits the criteria
# given by the block. This example will look
# through an array of hashes and return the element
# with the highest value with the key :value
# ary.find_best { |x, y| x[:value] < y[:value] }
def find_best &prc
best = fetch(0)
each { |e| best = e if yield(best, e) }
best
end
# Returns the elements of the given array as
# string with each element listed
# in the form "one, two and three".
def list
join(', ').reverse.sub(' ,', ' dna ').reverse
end
end
Extending Array, part 2
Another way to extend Array is to "mixin" the Enumerable module.
class Array
include Enumerable
end
This has several interesting methods (and also some that are already in Array). Use
any?
and all?
to determine if at least one element evalauates to true on the block, or all of them do.a = %w(one two three)
a.any? {|e| e.length == 5}
# => true
p a.all? {|e| e.length == 5}
# => false
You can find an element in an array using
find
(aka detect
). This method returns the first element for which the block evaulates to true. The method takes an optional parameter, this is returned if no element is found that fits.people.find { |e| e[:age] == 23 }
The
inject
method combines each element of the array.total_age = people.inject(0) { |memo, e| memo += e[:age] }
# => 69
The supplied parameter is the initial value (in this example, zero). This is technically optional, but going to be necessary in most cases (including this example) for the calculation to work in the first iteration. The memo is the ongoing value, so the increment is added to this.
Ref:
http://www.ruby-doc.org/core/classes/Array.html
http://ruby-doc.org/core/classes/Enumerable.html
Struggling with Ruby: Contents Page