Пример:
[12,23,987,43
Какой самый быстрый и эффективный способ удалить "[
",
используя, возможно, chop()
, но для первого символа?
Пример:
[12,23,987,43
Какой самый быстрый и эффективный способ удалить "[
",
используя, возможно, chop()
, но для первого символа?
Я предпочитаю использовать что-то вроде:
asdf = "[12,23,987,43" asdf[0] = '' p asdf # >> "12,23,987,43"
Я всегда ищу самый быстрый и читаемый способ делать вещи:
require 'benchmark'
N = 1_000_000
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
b.report('sub') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }
b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }
end
Работа на моем Mac Pro:
1.9.3
user system total real
[0] 0.840000 0.000000 0.840000 ( 0.847496)
sub 1.960000 0.010000 1.970000 ( 1.962767)
gsub 4.350000 0.020000 4.370000 ( 4.372801)
[1..-1] 0.710000 0.000000 0.710000 ( 0.713366)
slice 1.020000 0.000000 1.020000 ( 1.020336)
length 1.160000 0.000000 1.160000 ( 1.157882)
Обновление, чтобы включить еще один предложенный ответ:
require 'benchmark'
N = 1_000_000
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
b.report('sub') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }
b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }
b.report('eat!') { N.times { "[12,23,987,43".eat! } }
b.report('reverse') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end
Результат:
2.1.2
user system total real
[0] 0.300000 0.000000 0.300000 ( 0.295054)
sub 0.630000 0.000000 0.630000 ( 0.631870)
gsub 2.090000 0.000000 2.090000 ( 2.094368)
[1..-1] 0.230000 0.010000 0.240000 ( 0.232846)
slice 0.320000 0.000000 0.320000 ( 0.320714)
length 0.340000 0.000000 0.340000 ( 0.341918)
eat! 0.460000 0.000000 0.460000 ( 0.452724)
reverse 0.400000 0.000000 0.400000 ( 0.399465)
И еще с помощью /^./
, чтобы найти первый символ:
require 'benchmark'
N = 1_000_000
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
puts RUBY_VERSION
STR = "[12,23,987,43"
Benchmark.bm(7) do |b|
b.report('[0]') { N.times { "[12,23,987,43"[0] = '' } }
b.report('[/^./]') { N.times { "[12,23,987,43"[/^./] = '' } }
b.report('[/^\[/]') { N.times { "[12,23,987,43"[/^\[/] = '' } }
b.report('sub+') { N.times { "[12,23,987,43".sub(/^\[+/, "") } }
b.report('sub') { N.times { "[12,23,987,43".sub(/^\[/, "") } }
b.report('gsub') { N.times { "[12,23,987,43".gsub(/^\[/, "") } }
b.report('[1..-1]') { N.times { "[12,23,987,43"[1..-1] } }
b.report('slice') { N.times { "[12,23,987,43".slice!(0) } }
b.report('length') { N.times { "[12,23,987,43"[1..STR.length] } }
b.report('eat!') { N.times { "[12,23,987,43".eat! } }
b.report('reverse') { N.times { "[12,23,987,43".reverse.chop.reverse } }
end
Результат:
# >> 2.1.5
# >> user system total real
# >> [0] 0.270000 0.000000 0.270000 ( 0.270165)
# >> [/^./] 0.430000 0.000000 0.430000 ( 0.432417)
# >> [/^\[/] 0.460000 0.000000 0.460000 ( 0.458221)
# >> sub+ 0.590000 0.000000 0.590000 ( 0.590284)
# >> sub 0.590000 0.000000 0.590000 ( 0.596366)
# >> gsub 1.880000 0.010000 1.890000 ( 1.885892)
# >> [1..-1] 0.230000 0.000000 0.230000 ( 0.223045)
# >> slice 0.300000 0.000000 0.300000 ( 0.299175)
# >> length 0.320000 0.000000 0.320000 ( 0.325841)
# >> eat! 0.410000 0.000000 0.410000 ( 0.409306)
# >> reverse 0.390000 0.000000 0.390000 ( 0.393044)
Вот еще одно обновление более быстрого оборудования и более новой версии Ruby:
2.3.1
user system total real
[0] 0.200000 0.000000 0.200000 ( 0.204307)
[/^./] 0.390000 0.000000 0.390000 ( 0.387527)
[/^\[/] 0.360000 0.000000 0.360000 ( 0.360400)
sub+ 0.490000 0.000000 0.490000 ( 0.492083)
sub 0.480000 0.000000 0.480000 ( 0.487862)
gsub 1.990000 0.000000 1.990000 ( 1.988716)
[1..-1] 0.180000 0.000000 0.180000 ( 0.181673)
slice 0.260000 0.000000 0.260000 ( 0.266371)
length 0.270000 0.000000 0.270000 ( 0.267651)
eat! 0.400000 0.010000 0.410000 ( 0.398093)
reverse 0.340000 0.000000 0.340000 ( 0.344077)
Почему gsub настолько медленный?
После выполнения поиска/замены gsub
необходимо проверить возможные дополнительные совпадения, прежде чем он сможет определить, закончил ли он. sub
выполняет только один и заканчивается. Рассмотрим gsub
как минимум два вызова sub
.
Также важно помнить, что gsub
и sub
также могут быть ограничены плохо написанным регулярным выражением, которое встречается гораздо медленнее, чем поиск подстроки. Если возможно, привяжите регулярное выражение, чтобы получить максимальную скорость от него. Здесь есть ответы на "Переполнение стека", демонстрирующие, что для поиска требуется поиск, если вам нужна дополнительная информация.
Как и в ответ Пабло выше, но очиститель оттенков:
str[1..-1]
Вернет массив от 1 до последнего символа.
'Hello World'[1..-1]
=> "ello World"
Мы можем использовать срез для этого:
val = "abc"
=> "abc"
val.slice!(0)
=> "a"
val
=> "bc"
Используя slice!
, мы можем удалить любой символ, указав его индекс.
Я предпочитаю это:
str = "[12,23,987,43"
puts str[1..-1]
>> 12,23,987,43
Если вы всегда хотите снять ведущие скобки:
"[12,23,987,43".gsub(/^\[/, "")
Если вы просто хотите удалить первый символ, и знаете, что он не будет в многобайтном наборе символов:
"[12,23,987,43"[1..-1]
или
"[12,23,987,43".slice(1..-1)
Начиная с Ruby 2.5 вы можете использовать delete_prefix
или delete_prefix!
добиться этого в читабельной форме.
В этом случае "[12,23,987,43".delete_prefix("[")
.
Больше информации здесь:
https://blog.jetbrains.com/ruby/2017/10/10-new-features-in-ruby-2-5/
https://bugs.ruby-lang.org/issues/12694
'invisible'.delete_prefix('in') #=> "visible"
'pink'.delete_prefix('in') #=> "pink"
Обратите внимание, что вы также можете использовать это, чтобы удалить элементы из конца строки с помощью delete_suffix
и delete_suffix!
'worked'.delete_suffix('ed') #=> "work"
'medical'.delete_suffix('ed') #=> "medical"
https://bugs.ruby-lang.org/issues/13665
Редактировать:
Используя настройку Tin Man, он тоже выглядит довольно быстро (под последними двумя записями delete_p
и delete_p!
). Не совсем уместен предыдущий фаворит по скорости, хотя очень читабелен.
2.5.0
user system total real
[0] 0.174766 0.000489 0.175255 ( 0.180207)
[/^./] 0.318038 0.000510 0.318548 ( 0.323679)
[/^\[/] 0.372645 0.001134 0.373779 ( 0.379029)
sub+ 0.460295 0.001510 0.461805 ( 0.467279)
sub 0.498351 0.001534 0.499885 ( 0.505729)
gsub 1.669837 0.005141 1.674978 ( 1.682853)
[1..-1] 0.199840 0.000976 0.200816 ( 0.205889)
slice 0.279661 0.000859 0.280520 ( 0.285661)
length 0.268362 0.000310 0.268672 ( 0.273829)
eat! 0.341715 0.000524 0.342239 ( 0.347097)
reverse 0.335301 0.000588 0.335889 ( 0.340965)
delete_p 0.222297 0.000832 0.223129 ( 0.228455)
delete_p! 0.225798 0.000747 0.226545 ( 0.231745)
Неэффективная альтернатива:
str.reverse.chop.reverse
Например: a = "One Two Three"
1.9.2-p290 > a = "One Two Three"
=> "One Two Three"
1.9.2-p290 > a = a[1..-1]
=> "ne Two Three"
1.9.2-p290 > a = a[1..-1]
=> "e Two Three"
1.9.2-p290 > a = a[1..-1]
=> " Two Three"
1.9.2-p290 > a = a[1..-1]
=> "Two Three"
1.9.2-p290 > a = a[1..-1]
=> "wo Three"
Таким образом вы можете удалить один за другим первый символ строки.
Простой способ:
str = "[12,23,987,43"
removed = str[1..str.length]
Удивительный способ:
class String
def reverse_chop()
self[1..self.length]
end
end
"[12,23,987,43".reverse_chop()
(Примечание: предпочитайте простой способ:))
Благодаря @the-tin-man для составления тестов!
Увы, мне не очень нравится какое-либо из этих решений. Либо они требуют дополнительного шага для получения результата ([0] = ''
, .strip!
), либо они не очень семантичны/понятны о том, что происходит ([1..-1]
: "Um, диапазон от 1 до отрицательного 1? Yearg?" ), или они медленны или длинны для записи (.gsub
, .length
).
То, что мы пытаемся, является "сдвигом" (в языке Array), но возвращающим оставшиеся символы, а не тем, что было смещено. Позвольте использовать наш Ruby, чтобы сделать это возможным со строками! Мы можем использовать скоринговую операцию, но дать ей хорошее имя и взять аргумент, чтобы указать, сколько мы хотим отбросить фронт:
class String
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
Но мы можем сделать это быстрее, но неудобно. В то время как мы находимся в этом, для полноты, напишем a #shift
и #first
для String (почему у Array есть все самое интересное?), Взяв arg, чтобы указать, сколько символов мы хотим удалить с самого начала:
class String
def first(how_many = 1)
self[0...how_many]
end
def shift(how_many = 1)
shifted = first(how_many)
self.replace self[how_many..-1]
shifted
end
alias_method :shift!, :shift
end
Хорошо, теперь у нас есть хороший четкий способ вытаскивания символов с фронта строки, с помощью метода, который согласуется с Array#first
и Array#shift
(что действительно должно быть методом bang?). И мы можем легко получить модифицированную строку, а также с помощью #eat!
. Hm, мы должны поделиться нашей новой мощностью eat!
с Array? Почему бы и нет!
class Array
def eat!(how_many = 1)
self.replace self[how_many..-1]
end
end
Теперь мы можем:
> str = "[12,23,987,43" #=> "[12,23,987,43"
> str.eat! #=> "12,23,987,43"
> str #=> "12,23,987,43"
> str.eat!(3) #=> "23,987,43"
> str #=> "23,987,43"
> str.first(2) #=> "23"
> str #=> "23,987,43"
> str.shift!(3) #=> "23,"
> str #=> "987,43"
> arr = [1,2,3,4,5] #=> [1, 2, 3, 4, 5]
> arr.eat! #=> [2, 3, 4, 5]
> arr #=> [2, 3, 4, 5]
Это лучше!
str = "[12,23,987,43"
str[0] = ""
class String
def bye_felicia()
felicia = self.strip[0] #first char, not first space.
self.sub(felicia, '')
end
end
Использование регулярного выражения:
str = 'string'
n = 1 #to remove first n characters
str[/.{#{str.size-n}}\z/] #=> "tring"
Я считаю хорошим решением быть str.delete(str[0])
для его читабельности, хотя я не могу подтвердить его производительность.
list = [1,2,3,4] list.drop(1)
# => [2,3,4]
List удаляет один или несколько элементов с начала массива, не изменяет массив и возвращает сам массив вместо удаленного элемента.