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