All but last element of Ruby array
RubyRuby Problem Overview
Let's say I have a Ruby array
a = [1, 2, 3, 4]
If I want all but the first item, I can write a.drop(1)
, which is great. If I want all but the last item, though, I can only think of this way
a[0..-2] # or
a[0...-1]
but neither of these seem as clean as using drop
. Any other built-in ways I'm missing?
Ruby Solutions
Solution 1 - Ruby
Perhaps...
a = t # => [1, 2, 3, 4]
a.first a.size - 1 # => [1, 2, 3]
or
a.take 3
or
a.first 3
or
a.pop
which will return the last and leave the array with everything before it
or make the computer work for its dinner:
a.reverse.drop(1).reverse
or
class Array
def clip n=1
take size - n
end
end
a # => [1, 2, 3, 4]
a.clip # => [1, 2, 3]
a = a + a # => [1, 2, 3, 4, 1, 2, 3, 4]
a.clip 2 # => [1, 2, 3, 4, 1, 2]
Solution 2 - Ruby
Out of curiosity, why don't you like a[0...-1]
? You want to get a slice of the array, so the slice operator seems like the idiomatic choice.
But if you need to call this all over the place, you always have the option of adding a method with a more friendly name to the Array class, like DigitalRoss suggested. Perhaps like this:
class Array
def drop_last
self[0...-1]
end
end
Solution 3 - Ruby
Another cool trick
>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
Solution 4 - Ruby
I do it like this:
my_array[0..-2]
Solution 5 - Ruby
If you want to perform a pop()
operation on an array (which is going to result in the last item deleted), but you're interested in obtaining the array instead of a popped element, you can use tap(&:pop)
:
> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
Solution 6 - Ruby
How about augmenting the drop method itself, for example like this?
class Array
def drop(n)
n < 0 ? self[0...n] : super
end
end
Then you can use a negative size to remove elements from the end, like so:
[1, 2, 3, 4].drop(-1) #=> [1, 2, 3]
[1, 2, 3, 4].drop(-2) #=> [1, 2]
Solution 7 - Ruby
a[0...-1]
seems like the best way. The array slicing syntax was created for exactly this purpose...
Alternatively, if you don't mind modifying the array in place, you could just call a.pop
:
>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
Solution 8 - Ruby
To get rid of the last element in one line with the remainder returning
[1, 2, 4, 5, 6].reverse.drop(1).reverse
Seriously though,
[1,2,3,4][0..-2]
#=> [1,2,3]
Solution 9 - Ruby
This is the way:
[1,2,3,4,5][0..-1-1]
But let's explain how this works:
a = [1,2,3,4,5]
Next example will return all records, from 0 position to last
a[0..-1]
=> [1, 2, 3, 4, 5]
Next example will return records from 1 position to last
a[1..-1]
=> [2, 3, 4, 5]
And here you have what you need. Next example will return records from 0 position to last-1
a[0..-1-1]
=> [1, 2, 3, 4]
Solution 10 - Ruby
Have you tried "take"
a.take(3)
Solution 11 - Ruby
Answer: a.τwτ
, but you have to install Pyper first...
Pyper intro: Do you know Lispy car
and cdr
returning "first" and "rest" of the array? Just for the needs like yours, I made an extension of this Lispy mechanism. It's called pyper
, and it allows you to access also 2nd, rest from 2nd, 3rd, rest from 3d, and also last, everything except last etc. That wouldn't be much to write about, but it also allows letter composition, just like caar
, cadr
, cdadar
etc. known from Lisp:
# First, gem install pyper
require 'pyper'
include Pyper
a = %w/lorem ipsum dolor sit amet/
# To avoid confusion with other methods, and also because it resembles a rain gutter,
# Greek letter τ is used to delimit Pyper methods:
a.τaτ #=> "lorem"
a.τdτ #=> ["ipsum", "dolor", "sit", "amet"]
a.τbτ #=> "ipsum"
a.τeτ #=> ["dolor", "sit", "amet"]
a.τcτ #=> "dolor" (3rd)
a.τzτ #=> "amet" (last)
a.τyτ #=> "sit" (2nd from the end)
a.τxτ #=> "dolor" (3rd from the end)
and finally, the answer to your question:
a.τwτ #=> ["lorem", "ipsum", "dolor", "sit"] (all except last)
There is more:
a.τuτ #=> ["lorem", "ipsum", "dolor"] (all except last 2)
a.τ1τ #=> ["lorem", "ipsum"] (first 2)
a.τ8τ #=> (last 2)
a.τ7τ #=> (last 3)
Compositions:
a.τwydτ #=> "olor" (all except 1st letter of the last word of all-except-last array)
There are also more command characters than just a..f
, u..z
and 0..9
, most notably m
, meaning map:
a.τwmbτ #=> ["o", "p", "o", "i"] (second letters of all-except-last array)
But other command characters are too hot and not very easy to use at the moment.
Solution 12 - Ruby
This makes a new array with all but the last elements of the original:
ary2 = ary.dup
ary2.pop
Note that a few others have suggested using #pop. If you are ok modifying the array in place, that's fine. If you aren't ok with that, then dup the array first, as in this example.
Solution 13 - Ruby
I often find myself wanting all but the last n elements of an array. I've rigged up my own function to do this in a way that I find more readable than other solutions:
class Array
def all_but_the_last(n)
self.first(self.size - n)
end
end
Now you can do the following:
arr = ["One", "Two", "Three", "Four", "Five"]
# => ["One", "Two", "Three", "Four", "Five"]
arr.all_but_the_last(1)
# => ["One", "Two", "Three", "Four"]
arr.all_but_the_last(3)
# => ["One", "Two"]
arr.all_but_the_last(5)
# => []
arr.all_but_the_last(6)
# ArgumentError: negative array size
I've deliberately allowed for the ArgumentError so that the caller is responsible for how they use this method. I'd love to hear comments/criticisms of this approach.
Solution 14 - Ruby
a = [1,2,3,4]
a[0..(a.length - 2)]
=> [1,2,3]