In this post, I will dive into Arrays
. There are several methods we use every day, methods we use sometimes and methods we don’t know they even exist.
Basics
It’s a boring definition, but we all need to remember it:
Array indexing starts at 0. A negative index is assumed to be relative to the end of the array—that is, an index of -1 indicates the last element of the array, -2 is the next to last element in the array, and so on.
The first logical question arises: how can we create an array?
array = Array.new => []
or
array = [] => []
Arrays can contain different types of objects, integer, string or float – it doesn’t matter.
array = [1, 2, "Super Mario", 2.4, "Batman", 100] => [1, 2, "Super Mario", 2.4, "Batman", 100]
or
Array.new(3) => [nil, nil, nil]
or
Array.new(3, true) => [true, true, true]
As we know, Ruby is a completely object-oriented language, so arrays are represented as objects.
The deeper you go, the more interesting it gets
Let’s start with the most used iterator method: #each
. It is a method we’ve seen dozens of times and will see it dozens of times again. #each
comes pre-packaged with Array
and Range
classes, basically it goes through #each
element in the object you’ve called and passed it to the block you’ve specified. It will also return the original collection that it was called on:
[1, 3, 4, 1, 2].each {|n| puts "#{n}! "} 1! 3! 4! 1! 2! => [1, 3, 4, 1, 2]
There might be a case when you need to know in whicharray
position you are.each_with_index
, will do the job:
%w{Ruby is cool and provides us with another syntax for arrays}.each_with_index {|item, index| puts "position #{index} for #{item}"} position 0 for Ruby position 1 for is position 2 for cool position 3 for and position 4 for provides position 5 for us position 6 for with position 7 for another position 8 for syntax position 9 for for position 10 for arrays => ["Ruby", "is", "cool", "and", "provides", "us", "with", "another", "syntax", "for", "arrays"]
Let’s say we need to separate even
numbers from uneven
number. There are hundreds of ways how we can manage that, but then select
kicks in and saves us.
%w{1 2 3 4 5 6 7 8 9 10 11 112 123 1432}.select { |num| num%2==0 } => []
WOOOPS, it hasn’t worked as expected, but why? The answer for this one is pretty simple, we just need to check what has this %w{1 2 3 4 5 6 7 8 9 10 11 112 123 1432}
returned to us:
%w{1 2 3 4 5 6 7 8 9 10 11 112 123 1432} => ["1", "2", "3", "4", "5", "6", "7", "8", "9", "10", "11", "112", "123", "1432"]
The problem is obvious: we can’t divide the string or do any mathematical actions with strings.
%q => Single quoted string %Q or % => Double quoted string %w or %W => Array of tokens %r => Regular Expression %x => Shell Command %i => Array of Symbols
To avoid this let me switch back to [ ... ]
and we will not come across this pitfall again. I always say: simpler the better. When we are using [ ... ]
we don’t have to worry about what will be thrown back to us, just as in this case. But remember, it might be handy one day.
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 112, 123, 1432].select { |num| num%2==0 } => [2, 4, 6, 8, 10, 112, 1432]
and for uneven numbers, we just need to change from ==
to !=
[1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 112, 123, 1432].select { |num| num%2!=0 } => [1, 3, 5, 7, 9, 11, 123]
I would say, that was easy.
Where would we be without data manipulation?
In one of our recent projects, we were receiving information from many different health data providers and we needed to save in our system. At first, it didn’t sound too bad, but each provider sent different data with different structure, so we needed to #map
them before saving.
For example, let’s imagine we have few users and we want to automatically create them emails based on their full names. #map
is a life saver here:
users = ["Dalton Brown", "Ralph Braun", "Keara Mueller", "Suzanne Schuppe", "Trisha Batz"] users.map { |user| user.downcase.tr(" ", "_") + "@your_site.com" }
And the result is :
=> ["dalton_brown@your_site.com", "ralph_braun@your_site.com", "keara_mueller@your_site.com", "suzanne_schuppe@your_site.com", "trisha_batz@your_site.com"]
The unknown
I’ve lied, these are not “The unknown” methods, these are rather less known but still used methods, they’re all well documented and you should take a look at these secrets as they might get handy some day.
A quick way how you can remove the last element in your array is #pop
:
users = ["Dalton Brown", "Ralph Braun", "Keara Mueller", "Suzanne Schuppe", "Trisha Batz"] users.pop => "Trisha Batz" > users.pop => "Suzanne Schuppe" > users => ["Dalton Brown", "Ralph Braun", "Keara Mueller"]
Or even another handier way would be #uniq
and #uniq!
, but, please, bear in mind the difference.
#uniq
will return a new array by removing duplicate values in self,
whereas
#uniq!
will remove duplicate elements from self.
example_array = ["x", "z", "z", "z", "a", "b", "b"]
> example_array.uniq => ["x", "z", "a", "b"] > example_array => ["x", "z", "z", "z", "a", "b", "b"]
and
> example_array.uniq! => ["x", "z", "a", "b"] > example_array => ["x", "z", "a", "b"]
Ohhh… do you need to group your array? Then it’s already there for you #group_by
:
users = ["Dalton Brown", "Ralph Braun", "Keara Mueller", "Suzanne Schuppe", "Trisha Batz"]
users.group_by{|name| name.length} => {12=>["Dalton Brown"], 11=>["Ralph Braun", "Trisha Batz"], 13=>["Keara Mueller"], 15=>["Suzanne Schuppe"]}
Nice, right?
By the way, in this result, you see it has returned Hash
and we will speak about that next time.
Conclusion / lesson
Dig, dig and dig again! You don’t have to invent the new wheel, there are dozens of these tiny methods that can help you or tumble you if you misuse them. I once tripped on #reduce
: I thought it would do the job, but I had blocked myself for 2 days, just because I misused it and had to fix the damaged data. Just think twice in every situation: should I or should I not use it and what consequences will it have?