Все, кроме последнего элемента массива Ruby

140

Скажем, у меня есть массив Ruby

a = [1, 2, 3, 4]

Если мне нужно все, кроме первого, я могу написать a.drop(1), и это здорово. Если я хочу все, кроме последнего , я могу думать только об этом

a[0..-2]   # or
a[0...-1]

но ни один из них не кажется таким чистым, как использование drop. Какие-либо другие встроенные способы мне не хватает?

Питер
источник
Согласно globalnerdy.com/2008/07/10/… , падение будет на рубине 1.9, а не на рубине 1.8.6
Эндрю Гримм
А как насчет производительности ... Если бы я использовал эти ответы в итерациях по 1000 раз ... какой из них выиграл бы?
Ninad
Другими словами, какое решение не проходит через массив под капотом?
Ninad
другой способ, a - ([размер])
Джон

Ответы:

130

Возможно ...

a = t               # => [1, 2, 3, 4]
a.first a.size - 1  # => [1, 2, 3]

или

a.take 3

или

a.first 3

или

a.pop

который вернет последнее и оставит массив со всем до него

или заставьте компьютер работать на обед:

a.reverse.drop(1).reverse

или

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]
DigitalRoss
источник
5
Добавление метода Arrayкажется мне лучшим подходом. Большинство проектов заканчиваются core_ext.rbфайлом с такими небольшими расширениями. Некоторые библиотеки практически все являются такими расширениями: ActiveSupportнапример.
rfunduk
Это интересно, мне интересно, насколько это распространено. Что люди думают о поэзии?
DigitalRoss,
5
Как кто-то может представить этот clipметод сообществу Ruby? Я действительно думаю, что это должно быть там, а исправление обезьян - неправильная вещь .
Droogans 01
7
Мне нравится a.reverse.drop(1).reverseстратегия. ;-)
Alex
93

Из любопытства, почему тебе не нравится a[0...-1]? Вы хотите получить срез массива, поэтому оператор среза кажется идиоматическим выбором.

Но если вам нужно вызвать это повсюду, у вас всегда есть возможность добавить метод с более понятным именем в класс Array, как предлагал DigitalRoss. Возможно так:

class Array
    def drop_last
        self[0...-1]
    end
end
Мирко Фрёлих
источник
Когда капля такая чистая, кажется, что там много беспорядка. это не имеет большого значения, но с первого взгляда сложно подтвердить, что это именно так. Между drop_lastпрочим, я предпочитаю ваше имя ...
Питер,
Мне нравится использовать -1 намного элегантнее, чем использовать .length
Will Nathan
Любопытно, что означает третье .?
Джошуа Пинтер
5
... означает исключение последнего элемента, -1 - последний элемент. Если вы поставили две точки, тогда он будет включать последний элемент, три точки, тогда он не будет включать последний элемент.
ckim
Будьте осторожны, используя оператор среза для получения хвоста массива: он может вернуть nil: [][1..-1]-> nil, [][0...-1]->[]
Майкл
57

Еще один крутой трюк

>> *a, b = [1,2,3]
=> [1, 2, 3]
>> a
=> [1, 2]
>> b
=> 3
Монреальмайк
источник
1
Приятно, не знала, что Руби это есть; так a, *b = [1,2,3]что позвольте нам взглянуть на массив в классическом стиле car / cdr.
Nobbynob Littlun
Честно говоря, я даже не помню, чтобы писал этот комментарий: D удалил его сейчас ...
Петр Бела
Оооочень просто и красиво. THX
microspino
44

Если вы хотите выполнить pop()операцию с массивом (что приведет к удалению последнего элемента), но вы заинтересованы в получении массива вместо всплывающего элемента, вы можете использовать tap(&:pop):

> arr = [1, 2, 3, 4, 5]
> arr.pop
=> 5
> arr
=> [1, 2, 3, 4]
> arr.tap(&:pop)
=> [1, 2, 3]
когитоя
источник
Этот ответ семантически имеет наибольший смысл для этого пользователя. Операции зеркала под рукой, и в нем используются слова, которые легко интерпретировать && кратко.
Джером
2
Это какой-то ловкий Рубин.
emptywalls 05
38

Я так делаю:

my_array[0..-2]
Pixelearth
источник
2
Это работает фантастически. Я не понимаю, почему существует ряд гораздо более сложных ответов. Это новое дополнение Ruby?
Джошуа Пинтер
@JoshuaPinter существует с самого начала . Я согласен, что это лучший подход.
Julien
23

Как насчет расширения самого метода drop, например, вот так?

class Array
  def drop(n)
    n < 0 ? self[0...n] : super
  end
end

Затем вы можете использовать отрицательный размер, чтобы удалить элементы с конца, например:

[1, 2, 3, 4].drop(-1) #=> [1, 2, 3]
[1, 2, 3, 4].drop(-2) #=> [1, 2]
Axelarge
источник
19

a[0...-1]кажется лучшим способом. Синтаксис нарезки массива был создан именно для этой цели ...

В качестве альтернативы, если вы не возражаете против изменения массива на месте, вы можете просто вызвать a.pop:

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]
dbr
источник
вы также можете назначить последний элемент переменной для дальнейшего использования:b = a.pop
Виктор
12

Чтобы избавиться от последнего элемента в одной строке с возвращением остатка

[1, 2, 4, 5, 6].reverse.drop(1).reverse

Если серьезно,

[1,2,3,4][0..-2]
#=> [1,2,3]
boulder_ruby
источник
11

Это способ:

[1,2,3,4,5][0..-1-1]

Но давайте объясним, как это работает:

a = [1,2,3,4,5]

Следующий пример вернет все записи, от 0 позиции до последней.

a[0..-1]
=> [1, 2, 3, 4, 5]

В следующем примере будут возвращены записи с 1 позиции до последней.

a[1..-1]
=> [2, 3, 4, 5]

И вот то, что вам нужно. В следующем примере будут возвращены записи с позиции 0 до последней-1.

a[0..-1-1]
=> [1, 2, 3, 4]
Фрэн Мартинес
источник
2
Вы можете написать -2вместо -1-1.
bfontaine 01
Вы можете сделать a[0...-1](обратите внимание на третью точку) и получить тот же результат a[0..-1-1], что и, потому что третья точка указывает исключить конечный элемент. См. Это для более подробной информации.
Жюльен
7

Вы пробовали "взять"

a.take(3) 
Майк Бакби
источник
6
в общем это есть a.take(a.size - 1); да, рассматривал этот вариант.
Питер,
2

Ответ: a.τwτ но сначала нужно установить Pyper ...

Пайпер интро: знаете ли вы Lispy carи cdrвозвращение «первого» и «отдых» из массива? Просто для таких же нужд я сделал расширение этого Lispy-механизма. Он называется pyper, и он позволяет вам получить доступ также к 2-му, отдыху со 2-го, 3-го, отдыху из 3-го, а также к последнему, ко всему, кроме последнего и т. Д. Об этом нечего было бы писать, но он также позволяет составлять буквы, как и caar, cadrи cdadarт.д., известные из 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)

и, наконец, ответ на ваш вопрос:

a.τwτ #=> ["lorem", "ipsum", "dolor", "sit"] (all except last)

Есть еще:

a.τuτ #=> ["lorem", "ipsum", "dolor"] (all except last 2)
a.τ1τ #=> ["lorem", "ipsum"] (first 2)
a.τ8τ #=> (last 2)
a.τ7τ #=> (last 3)

Композиции:

a.τwydτ #=> "olor" (all except 1st letter of the last word of all-except-last array)

Также есть больше командных символов, чем просто a..f, u..zи 0..9, что особенно важно m, означает карту:

a.τwmbτ #=> ["o", "p", "o", "i"] (second letters of all-except-last array)

Но другие командные символы слишком популярны и не очень просты в использовании на данный момент.

Борис Ститницкий
источник
1
Я читаю это 1 апреля, поэтому решил, что это шутка ... нет. Понятия не имел, что эта штука существует для Руби. :)
Джошуа Пинтер
1

Это создает новый массив со всеми элементами оригинала, кроме последних:

ary2 = ary.dup
ary2.pop

Обратите внимание, что некоторые другие предложили использовать #pop. Если вы можете изменить массив на месте, ничего страшного. Если вас это не устраивает, сначала скопируйте массив, как в этом примере.

алегскогс
источник
1
Некоторые другие предложили использовать #pop, если вы можете изменить массив на месте. Если вас это не устраивает, сначала скопируйте массив, как в этом примере.
alegscogs
Это важный комментарий. Вы можете просто добавить это к своему ответу. Поскольку #pop не вызывает шума (!), Тот факт, что он изменяет исходный массив, может ускользнуть от людей.
mjnissim
Это неэффективно, если массив большой.
juliangonzalez
1

Я часто обнаруживаю, что мне нужны все, кроме последних n элементов массива. Я настроил свою собственную функцию, чтобы сделать это более читаемым, чем другие решения:

class Array
  def all_but_the_last(n)
    self.first(self.size - n)
  end
end

Теперь вы можете сделать следующее:

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

Я намеренно допустил ошибку ArgumentError, чтобы вызывающая сторона отвечала за использование этого метода. Я хотел бы услышать комментарии / критику этого подхода.

Сумья
источник
-1
a = [1,2,3,4]

a[0..(a.length - 2)]
=> [1,2,3]
Джордж Лукас
источник