Советы по игре в гольф в Руби

62

Какие общие советы вы можете дать для игры в гольф в Ruby?

Я ищу идеи, которые могут быть применены к задачам по коду для гольфа в целом, которые характерны для Ruby. (Например, «Удалить комментарии» не будет ответом.)

Пожалуйста, оставьте один совет за ответ.

grokus
источник
Кто-то должен написать язык под названием Rub, который использует один символ Unicode для каждого токена Ruby, вроде Jelly и Pyth :)
Марк Томас

Ответы:

46
  • Числа 100 до 126 можно записать в виде ?dдо ?~1.8.
  • На аналогичном примечании, если вам нужна односимвольная строка в 1.9? X короче, чем "x".
  • Если вам нужно напечатать строку без добавления новой строки, $><<"string"она короче print"string".
  • Если вам нужно прочитать несколько строк ввода $<.map{|l|...}короче while l=gets;...;end. Также вы можете использовать, $<.readчтобы прочитать все это сразу.
  • Если вы должны читать из файла, $<и getsбудете читать из файла вместо стандартного ввода, если имя файла в ARGV. Таким образом, golfiest способ переописать catбудет: $><<$<.read.
sepp2k
источник
1
? x в общем случае дает код ascii, так что вы можете реально получить все печатные формы из двух символов. 1.9 отличается, 'a'.ord возвращает число ascii, но на четыре байта длиннее десятичной версии.
Hiato
8
Еще более удачный способ реализации cat- оставить файл ruby ​​полностью пустым (0 байт) и настаивать на том, чтобы его запускали из командной строки с -pфлагом.
Даньеро
1
или, из собственного ответа @ daniero ,puts *$<
не то, что Чарльз
1
Так что в 1.8 все, что мне нужно сделать, это пойти? ~ И он вернется 126?
Просто Красивое Искусство
5
Вы можете выйти за рамки 126, используя мысли как или , или если вы достаточно сумасшедший:?﷽.ord=65021
Просто Красивое Искусство
32

Используйте оператор splat, чтобы получить хвост и голову массива:

head, *tail = [1,2,3]
head => 1
tail => [2,3]

Это также работает по-другому:

*head, tail = [1,2,3]
head => [1,2]
tail => 3

Используйте *метод со строкой в ​​массиве для объединения элементов:

[1,2,3]*?,
=> "1,2,3"
Арно Ле Блан
источник
27
  • Используйте abortдля завершения программы и печати строки в STDERR - короче, чем putsпослеexit
  • Если вы читаете строку с gets, вы можете использовать ее ~/$/для определения ее длины (это не учитывает завершающий символ новой строки, если он существует)
  • Используйте, []чтобы проверить, содержит ли строка другую:'foo'['f'] #=> 'f'
  • Используйте trвместо gsubсимвольных замен:'01011'.tr('01','AB') #=> 'ABABB'
  • Если вам нужно удалить завершающие символы новой строки, используйте chopвместоchomp
Lowjacker
источник
2
+1 за abortи~/$/
J -_- L
Пожалуйста, объясните, как использовать~/$/
Матье CAROFF
@MathieuCAROFF каждый раз, когда вы вызываете gets, его результат сохраняется в $_переменной. /regex/ ~= stringвозвращает индекс первого совпадения. Вызов ~регулярного выражения эквивалентен /regex/ ~= $_. Так что это будет что-то вродеs=gets;l= ~/$/
Cyoce
20

Конец твой end.

Попробуйте удалить endиз вашего кода.

Не используйте def...endдля определения функций. Сделайте лямбду с оператором new -> в Ruby 1.9. (Оператор -> является «стабильной лямбда» или «тире ракета» .) Это сохраняет 5 символов для каждой функции.

# 28 characters
def c n
/(\d)\1/=~n.to_s
end

# 23 characters, saves 5
c=->n{/(\d)\1/=~n.to_s}

Вызов метода c nили c(n). Лямбда звонки есть c[n]. Сменяя друг c nна c[n]затраты 1 символ, так что если вы можете использовать c nболее чем в 5 раз, а затем сохранить этот метод.

Все методы, которые принимают do...endблоки, могут {...}вместо этого принимать блоки. Это сохраняет от 3 до 5 символов. Если приоритет {...}слишком велик, используйте скобки, чтобы исправить это.

# 48 characters
(?a..?m).zip (1..5).cycle do|a|puts a.join','end

# WRONG: passes block to cycle, not zip
(?a..?m).zip (1..5).cycle{|a|puts a.join','}

# 45 characters, saves 3
(?a..?m).zip((1..5).cycle){|a|puts a.join','}

Заменить if...else...endна троичный оператор ?: . Если в ветке есть два или более операторов, заключите их в скобки.

# 67 characters
if a<b
puts'statement 1'
puts'statement 2'else
puts'statement 3'end

# 62 characters, saves 5
a<b ?(puts'statement 1'
puts'statement 2'):(puts'statement 3')

Вероятно, у вас нет whileили untilциклов, но если у вас есть, то напишите их в форме модификатора.

(a+=1
b-=1)while a<b
kernigh
источник
Нужны ли круглые скобки puts'statement 3'?
Cyoce
15

Дополнение к w0lf

При работе с массивами .compactможно заменить -[nil]на 2 символа.

В сочетании с выше -> вы можете сделать его еще короче, -[p]чтобы сохранить еще 2 символа.

villu164
источник
14

По возможности используйте короткие предопределенные переменные, например, $*вместо ARGV. Там хороший список из них здесь , наряду с большим количеством другой полезной информации.

Nemo157
источник
12

Когда вы используете интерполяцию строк (как следует из публикации Мартина Бюттнера ), вам не нужны фигурные скобки, если перед вашим объектом стоит символ ( $, @). Полезно для магических переменных, таких как $_, $&и $1т.д:

puts "this program has read #$. lines of input"

Также, если вам нужно вывести переменную больше, чем вы ее используете, вы можете сохранить несколько байтов.

a=42; puts "here is a: #{a}"; puts "here is a again: #{a}"
$b=43; puts "here is b: #$b"; puts "here is b again: #$b"
daniero
источник
11

Если вам нужно найти, находится ли определенный элемент eвнутри диапазона r, вы можете использовать

r===e

вместо более длинного:

r.cover?(e) # only works if `r.exclude_end?` is false

или же

r.member?(e)

или же

r.include?(e)
Кристиан Лупаску
источник
3
r===eДаже не короче?
akuhn
@akuhn Да, это так. Намного короче. Спасибо за указание на это, это помогло мне сократить код на 10 символов, что огромно: codegolf.stackexchange.com/a/6125/3527
Кристиан Лупаску,
1
Пожалуйста. Все, что может быть использовано в операторе switch, ===реализовано.
akuhn
10

$_ последняя прочитанная строка.

  • print - если аргумент не указан, выведите содержимое $_
  • ~/regexp/ - Короче для $_=~/regexp/

В Ruby 1.8 у вас есть четыре метода, Kernelкоторые работают с $_:

  • chop
  • chomp
  • sub
  • gsub

В Ruby 1.9 эти четыре метода существуют, только если ваш скрипт использует -nили -p.

Если вы хотите печатать некоторую переменную часто, используйте trace_var(:var_name){|a|p a}

Hauleth
источник
2
Они доступны только при запуске Ruby с параметром -pили -n. Ссылка.
Даррен Стоун
1
Похоже, что trace_varработает только с глобальными переменными $
Даниеро
10

Используйте строковую интерполяцию!

  1. Заменить to_s. Если вам нужны круглые скобки вокруг того, что вы хотите превратить в строку, to_sэто на два байта больше, чем интерполяция строки:

    (n+10**i).to_s
    "#{n+10**i}"
    
  2. Заменить конкатенацию. Если вы объединяете что-то, окруженное двумя другими строками, интерполяция может сэкономить вам один байт:

    "foo"+c+"bar"
    "foo#{c}bar"
    

    Также работает, если промежуточное звено само объединено, если вы просто перемещаете объединение внутри интерполяции (вместо использования нескольких интерполяций):

    "foo"+c+d+e+"bar"
    "foo#{c+d+e}bar"
    
Мартин Эндер
источник
10

Избегайте lengthвif a.length<n

length6 байт, немного дороже в коде гольф. во многих ситуациях вы можете вместо этого проверить, есть ли в массиве что-либо в данной точке. если вы nilпропустите последний индекс, который вы получите , значение Falsey.

Так что вы можете изменить:

if a.length<5до if !a[4]-5 байт

или же

if a.length>5до if a[5]-6 байт

или же

if a.length<nв if !a[n-1]течение -3 байтов

или же

if a.length>nдо if a[n]-6 байт

Примечание : будет работать только с массивом всех истинных значений. наличие nilили falseвнутри массива может вызвать проблемы.

MegaTom
источник
4
Я всегда использую size... Но это определенно лучше. Кстати, работает Stringтоже.
manatwork
10

Не используйте trueи falseключевые слова.

Использование:

  • !pза true(спасибо, гистократ!)
  • !0для false. Если все, что вам нужно, это ложное значение, то вы можете просто использовать p(что возвращает nil).

чтобы сохранить некоторые символы.

Кристиан Лупаску
источник
1
Если вам действительно не нужно true(то есть, если истинного значения достаточно, как в условии if), вам даже не нужно !!.
Мартин Эндер
4
И аналогично, p(который оценивает nil) является более коротким значением Лжи. Это означает самый короткий путь , чтобы получить trueэто !p.
гистократ
@histocrat хороший момент! Я отредактировал свой ответ.
Кристиан Лупаску,
9

Если вы когда - нибудь понадобится , чтобы получить число от ARGV, getили что - то подобное сделать что - то , что много раз, вместо вызова to_iна него, вы можете просто использовать , ?1.upto x{do something x times}где х представляет собой строку.

Таким образом, использование ?1.upto(a){}вместо x.to_i.times{}сэкономит вам 2 символа.

Вы также можете переписать такие вещи, как p 1 while 1или p 1 if 1как p 1while 1илиp 1if 1

Этот пример не очень полезен, но его можно использовать для других целей.

Также, если вам нужно присвоить первый элемент массива переменной, a,=cбудут сохранены два символа, а неa=c[0]

аддисон
источник
9

Новые функции в Ruby 2.3 и 2.4

Хорошо быть в курсе новых языковых функций, которые помогут вашей игре в гольф. В последних рубинах есть несколько замечательных.

Ruby 2.3

Оператор безопасной навигации: &.

Когда вы вызываете метод, который может возвращать, nilно вы хотите связать дополнительные вызовы метода, если это не так, вы тратите впустую байты, обрабатывая nilслучай:

arr = ["zero", "one", "two"]
x = arr[5].size
# => NoMethodError: undefined method `size' for nil:NilClass

x = arr[5].size rescue 0
# => 0

«Оператор безопасной навигации» останавливает цепочку вызовов методов, если возвращается nilи возвращается nilдля всего выражения:

x = arr[5]&.size || 0
# => 0

Array#dig & Hash#dig

Глубокий доступ к вложенным элементам с красивым коротким именем:

o = { foo: [{ bar: ["baz", "qux"] }] }
o.dig(:foo, 0, :bar, 1) # => "qux"

Возвращает, nilесли попадает в тупик:

o.dig(:foo, 99, :bar, 1) # => nil

Enumerable#grep_v

Обратный Enumerable#grep-returns всех элементов , которые не соответствуют данному аргументу ( по сравнению с ===). Например grep, если дан блок, вместо него возвращается результат.

(1..10).grep_v 2..5 # => [1, 6, 7, 8, 9, 10]
(1..10).grep_v(2..5){|v|v*2} # => [2, 12, 14, 16, 18, 20]

Hash#to_proc

Возвращает Proc, который возвращает значение для данного ключа, что может быть очень удобно:

h = { N: 0, E: 1, S: 2, W: 3 }
%i[N N E S E S W].map(&h)
# => [0, 0, 1, 2, 1, 2, 3]

Ruby 2.4

Ruby 2.4 еще не выпущен, но он скоро появится и имеет несколько замечательных небольших функций. (Когда он выйдет, я дополню этот пост некоторыми ссылками на документы.) О большинстве из них я узнал из этого замечательного поста в блоге .

Enumerable#sum

Нет больше arr.reduce(:+). Теперь вы можете просто сделать arr.sum. Он принимает необязательный аргумент начального значения, который по умолчанию равен 0 для числовых элементов ( [].sum == 0). Для других типов вам необходимо указать начальное значение. Он также принимает блок, который будет применен к каждому элементу перед добавлением:

[[1, 10], [2, 20], [3, 30]].sum {|a,b| a + b }
# => 66

Integer#digits

Это возвращает массив цифр числа в порядке наименьшей значимости:

123.digits # => [3, 2, 1]

По сравнению, скажем 123.to_s.chars.map(&:to_i).reverse, это довольно мило.

В качестве бонуса он принимает необязательный аргумент radix:

a = 0x7b.digits(16) # => [11, 7]
a.map{|d|"%x"%d} # => ["b", "7"]

Comparable#clamp

Делает то, что говорит на банке:

v = 15
v.clamp(10, 20) # => 15
v.clamp(0, 10) # => 10
v.clamp(20, 30) # => 20

Поскольку он находится в Comparable, вы можете использовать его с любым классом, который включает Comparable, например:

?~.clamp(?A, ?Z) # => "Z"

String#unpack1

2-байтовая экономия более .unpack(...)[0]:

"👻💩".unpack(?U)    # => [128123]
"👻💩".unpack(?U)[0] # => 128123
"👻💩".unpack1(?U)   # => 128123

Точность аргумент Numeric#ceil, floorиtruncate

Math::E.ceil(1) # => 2.8
Math::E.floor(1) # => 2.7
(-Math::E).truncate(1) # => -2.7

Многократное присваивание в условных выражениях

Это вызывает ошибку в более ранних версиях Ruby, но допускается в 2.4.

(a,b=1,2) ? "yes" : "no" # => "yes"
(a,b=nil) ? "yes" : "no" # => "no"
Иордания
источник
Поле Math::E.ceil(1)для Math::E.ceil 1, и также для floorи truncate.
Просто Красивое Искусство
1
@SimplyBeautifulArt Я ожидаю, что кто-то, играющий в гольф в Ruby, сможет сделать этот прыжок самостоятельно.
Иордания
Ибо Enumerable#sum, .flatten.sumна 2 байта короче.sum{|a,b|a+b}
Asone Tuhid
(-Math::E).truncate(1)эквивалентно тому, -Math::E.truncate(1)что на 1 байт короче
Asone Tuhid
1
&.может использоваться с такой подпиской a&.[]i(на 1 байт короче a&.at i). Хотя, если требуются скобки, a||a[i]на 1 байт короче a&.[](i)илиa&.at(i)
Asone Tuhid
7

Научная запись часто может использоваться, чтобы сбрить полукокса или два:

x=1000
#versus
x=1e3
анонимный трус
источник
9
Примечание. Это вернет значение типа Float (1000.0) вместо Integer, что может привести к неточным результатам с большими числами.
Догберт
4
Ах, 1e2лучше, чем 100.0когда нужен процент.
Фрогз
Аналогично этому принципу, 1.0*на 1 символ короче.to_f
Unihedron
7

Используйте операторные методы вместо скобок

Допустим, вы хотите выразить a*(b+c). Из-за приоритета a*b+cне сработает (очевидно). Крутой способ Руби иметь операторов как методы приходит на помощь! Вы можете использовать, a.*b+cчтобы сделать приоритет *ниже, чем у +.

a*(b+c) # too long
a*b+c   # wrong
a.*b+c  # 1 byte saved!

Это может также работать с !и ~операторами ( такими вещами , как унарные +или унарный -не работает , потому что их методы -@и +@, экономя , ()но добавление .@)

(~x).to_s # too long
~x.to_s   # error
x.~.to_s  # 1 byte saved!
Cyoce
источник
6

Используйте ||вместо orи &&вместо and.

Помимо одного символа andвы можете сохранить пробелы (и, возможно, скобки) вокруг оператора.

p true and false ? 'yes' :'no'   #-> true (wrong result)
p (true and false) ? 'yes' :'no' #-> 'no'
p true&&false ? 'yes' :'no'      #-> 'no', saved 5 characters


p true or false ? 'yes' :'no'   #-> true (wrong result)
p (true or false) ? 'yes' :'no' #-> 'yes'
p true||false ? 'yes' :'no'      #-> 'yes', saved 4 characters

Если вы зациклились на массиве, который вы обычно используете each. Но mapзацикливается также на массив, и он на один символ короче.

Кнут
источник
6

Я только что попытался выполнить тест TDD для игры в гольф, то есть написать кратчайший код для прохождения спецификаций. Спецификации были что-то вроде

describe PigLatin do
  describe '.translate' do
    it 'translates "cat" to "atcay"' do
      expect(PigLatin.translate('cat')).to eq('atcay')
    end
    # And similar examples for .translate
  end
end

Ради код-гольфа не нужно создавать модуль или класс.

Вместо

module PigLatin def self.translate s;'some code'end;end

можно сделать

def(PigLatin=p).translate s;'some code'end

Спасает 13 символов!

С Шах
источник
7
Ха, очень тщательно. Мало того, что вы добавили необходимое поведение к PigLatin, но и @pig_latin, $pig_latinи 'pig'['latin'].
гистократ
@histocrat: Теперь я понял. Это потому translateчто было определено nil.
Эрик
6

Ядро # p - забавный метод.

Используйте p varвместо puts var. Это прекрасно работает с целыми числами и числами с плавающей запятой, но не со всеми типами. Он печатает кавычки вокруг строк, что, вероятно, не то, что вы хотите.

Используется с одним аргументом, pвозвращает аргумент после его печати.

Используется с несколькими аргументами, pвозвращает аргументы в массиве.

Используйте p(без аргументов) вместо nil.

Фабио Перес
источник
10
К сожалению, p 'some string'печатные издания "some string"и не только, some stringкоторый часто критикуют другие.
Патрик Осцити
1
В основном так p sже, как puts s.inspect, но он возвращаетсяs
Cyoce
6

Не используйте #each. Вы можете просто зациклить все элементы с помощью #map. Так что вместо

ARGV.each{|x|puts x}

Вы можете сделать то же самое в меньшем количестве байтов.

ARGV.map{|x|puts x}

Конечно, в этом случае puts $*будет еще короче.


Существуют литералы для рациональных и комплексных чисел:

puts 3/11r == Rational(3,11)
puts 3.3r == Rational(66,20)
puts 1-1.i == Complex(1,-1)

=> true
true
true

Вы можете использовать большинство байтов в строках. "\x01"(6 байтов) можно сократить до ""(3 байта). Если вам нужен только этот один байт, его можно сократить еще больше до ?(2 байта).

Точно так же вы можете сократить перевод строки следующим образом:

(0..10).to_a.join'
'

 => "0\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10"

Вы можете использовать ?\nи ?\tтакже, который на один байт короче, чем "\n"и "\t". Для запутывания, есть также? \ S, пробел.


Используйте константы вместо передачи аргументов, даже если вам нужно их изменить. Переводчик будет предупреждать stderr , но кого это волнует. Если вам нужно определить больше переменных, связанных друг с другом, вы можете связать их в цепочку следующим образом:

A=C+B=7+C=9

=> A=17, B=16, C=9

Это короче C=9;B=16;A=17или C=0;B=C+7;A=C+B.


Если вам нужен бесконечный цикл, используйте loop{...}. Петли неизвестной длины могут быть короче с другими петлями:

loop{break if'
'==f(gets)}

while'
'!=f(gets);end

Еще несколько трюков с gsub / regexp. Используйте специальные '\1'escape-символы вместо блока:

"golf=great short=awesome".gsub(/(\w+)=(\w+)/,'(\1~>\2)')

"golf=great short=awesome".gsub(/(\w+)=(\w+)/){"(#{$1}~>#{$2})")

И специальные переменные $1и т. Д., Если вам нужно выполнить операции. Имейте в виду, что они определены не только внутри блока:

"A code-golf challenge." =~ /(\w+)-(\w+)/
p [$1,$2,$`,$']

=> ["code", "golf", "A ", " challenge."] 

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

x+=1if$*<<A==????::??==??
blutorange
источник
«Пожалуйста, оставьте один совет за ответ». Также ?\nэто хорошо, но на самом деле не короче, чем ввод символа новой строки внутри кавычек. (то же самое для вкладки)
Мартин Эндер
И puts$*еще короче.
Cyoce
Я знаю, что вы пытались доказать свою точку зрения, но я почти уверен, что последний пример такой же, какx+=1;$*<<A
Asone Tuhid
6

Еще один способ использования оператора splat: если вы хотите назначить один литерал массива, *то левая часть короче скобок с правой стороны:

a=[0]
*a=0

С несколькими значениями вам даже не нужен оператор splat (спасибо гистократу за поправку):

a=[1,2]
a=1,2
Мартин Эндер
источник
Последний случай на самом деле не нуждается в сплате.
гистократ
@histocrat Ого, я думал, что второе значение будет просто отброшено в этом случае.
Мартин Эндер
1
Я не могу поверить, что я не знал их все время, что я играл в гольф в Руби.
Дверная ручка
6

Когда задача требует, чтобы вы вывели несколько строк, вам не нужно циклически просматривать результаты, чтобы напечатать каждую строку, например, массива. putsМетод будет выравниваться массив и распечатать каждый элемент в отдельной строке.

> a = %w(testing one two three)
> puts a
testing
one
two
three

Комбинируя оператор splat с #pвами, вы можете сделать его еще короче:

p *a

Оператор splat (технически *@метод, я думаю) также преобразует ваши перечисляемые не-массивы в массивы:

> p a.lazy.map{|x|x*2}
#<Enumerator::Lazy: #<Enumerator::Lazy: [1, 2, 3]>:map>

против

> p *a.lazy.map{|x|x*2}
2
4
6
daniero
источник
1
*@это не метод, сплат - это синтаксический сахар
Asone Tuhid
6

Сохраните несколько байтов при удалении повторяющихся элементов массива

a.uniq # before
a|[]   # after
    ^^

Если вы будете использовать пустой массив []в переменной, вы можете сохранить еще больше байтов:

a.uniq;b=[] # before
a|b=[]      # after
      ^^^^^
Cyoce
источник
2
Для первого случая на a&a1 байт короче
Asone Tuhid
5

Используйте Goruby вместо Ruby, что-то вроде сокращенной версии Ruby. Вы можете установить его с помощью RVM через

rvm install goruby

Goruby позволяет вам писать большую часть кода, как если бы вы писали на Ruby, но имеет встроенные дополнительные сокращения. Чтобы найти кратчайшие доступные сокращения для чего-либо, вы можете использовать вспомогательный метод shortest_abbreviation, например:

shortest_abbreviation :puts
#=> "pts"

Array.new.shortest_abbreviation :map
#=> "m"

String.new.shortest_abbreviation :capitalize
#=> "cp"

Array.new.shortest_abbreviation :join
#=> "j"

Также очень удобен псевдоним, sayдля putsкоторого можно сокращенно обозначить его s. Так что вместо

puts [*?a..?z].map(&:capitalize).join

теперь вы можете написать

s [*?a..?z].m(&:cp).j

печатать алфавит прописными буквами (что не очень хороший пример). Этот пост в блоге объясняет больше вещей и некоторые внутренние детали, если вы заинтересованы в дальнейшем чтении.

PS: не пропустите hметод ;-)

Патрик Осцити
источник
Прошло более 2 лет, и я наконец понял, что этот ответ мне напоминает ...
подземный
5

Чтобы присоединиться к массиву, вместо этого

[...].join

сделай это

[...]*''

который экономит 2 байта. Для объединения с разделителем используйте

[...]*?,
Markus
источник
5

Номера для подписки!

Я только что обнаружил это вчера. n[i]возвращает nбит в i-ой позиции. Пример:

irb(main):001:0> n = 0b11010010
=> 210
irb(main):002:0> n[0]
=> 0
irb(main):003:0> n[1]
=> 1
irb(main):004:0> n[2]
=> 0
irb(main):005:0> n[3]
=> 0
irb(main):006:0> n[4]
=> 1
irb(main):007:0> n[5]
=> 0
Cyoce
источник
И теперь вы можете использовать больше аргументов, таких какn[0..3]
Просто Красивое Искусство
4

Вы можете сохранить 2 символа и использовать

[*(...)]

вместо

(...).to_a

Например, предположим, что у нас есть диапазон, который мы хотим использовать в качестве массива:

(1..2000).to_a

Просто сделайте это так:

[*1..2000]  #  Parentheses around the (ran..ge) is not needed!

И теперь у вас есть свой диапазон в виде массива.

Джастин
источник
5
Я думаю [*1..2000]тоже работает?
Линн
4

<< трюк

a.push x

можно сократить до:

a<<x

для -4 байта.

MegaTom
источник
2
Примечание: это также работает для Strings
Cyoce
4

Array#assoc/rassoc

Если у вас есть массив массивов и вы хотите найти подмассив, который начинается с определенного значения, не используйте Enumerable#find, используйте Array#assoc:

a = [[0,"foo"],[0,"bar"],[1,"baz"],[0,"qux"]]
a.find{|x,|x==1} # => [1,"baz"]
a.assoc(1) # => [1,"baz"]

Это также хорошая замена Enumerable#any?в некоторых ситуациях.

Array#rassoc делает то же самое, но проверяет последний элемент подмассива:

a = [[123,"good"],[456,"good"]]
a.any?{|*,x|x=="bad"} # => false
a.rassoc("bad") # => nil
Иордания
источник
Для a.any?строки в rassoc примере, что делает |x,|? Чем он отличается от |x|?
Cyoce
@Cyoce Параметр блока деструктурирующий следует тем же правилам, что и назначение уничтожения того , так как x=[1,2]против x,=[1,2]. Используя мой пример выше, с |x|, в первой итерации xбудет [0,"foo"]. С |x,y|, xбудет 0и yбудет "foo". Точно так же, с |x,|, xбудет 0. Другими словами, он говорит , что «поставил первый элемент xи бросить все остальное прочь.
Иордания
Обратите внимание, что он не работает в обратном порядке, например |,y|, это SyntaxError, ergo |_,y|. Но я только сейчас понял, что |*,y|работает, что чище, чем использование переменной с именем _(но не короче).
Иордания