Все, кроме последнего элемента массива 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]

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]

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]

19

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

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

>> a = [1, 2, 3, 4]
>> a.pop
>> a
=> [1, 2, 3]

вы также можете назначить последний элемент переменной для дальнейшего использования:b = a.pop
— Виктор

12

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

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

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

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

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], что и, потому что третья точка указывает исключить конечный элемент. См. Это для более подробной информации.
— Жюльен


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, чтобы вызывающая сторона отвечала за использование этого метода. Я хотел бы услышать комментарии / критику этого подхода.


Используя наш сайт, вы подтверждаете, что прочитали и поняли нашу Политику в отношении файлов cookie и Политику конфиденциальности.
Licensed under cc by-sa 3.0 with attribution required.