All but last element of Ruby array

Ruby

Ruby 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)
a1τ #=> ["lorem", "ipsum"] (first 2)
a8τ #=> (last 2)
a7τ #=> (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]

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionPeterView Question on Stackoverflow
Solution 1 - RubyDigitalRossView Answer on Stackoverflow
Solution 2 - RubyMirko FroehlichView Answer on Stackoverflow
Solution 3 - RubymontrealmikeView Answer on Stackoverflow
Solution 4 - RubypixelearthView Answer on Stackoverflow
Solution 5 - RubykogitojaView Answer on Stackoverflow
Solution 6 - RubyaxelargeView Answer on Stackoverflow
Solution 7 - RubydbrView Answer on Stackoverflow
Solution 8 - Rubyboulder_rubyView Answer on Stackoverflow
Solution 9 - RubyFran MartinezView Answer on Stackoverflow
Solution 10 - RubyMike BuckbeeView Answer on Stackoverflow
Solution 11 - RubyBoris StitnickyView Answer on Stackoverflow
Solution 12 - RubyalegscogsView Answer on Stackoverflow
Solution 13 - RubySoumyaView Answer on Stackoverflow
Solution 14 - RubyGeorge LucasView Answer on Stackoverflow