Разрежьте каждый символ из массива


Что является наиболее эффективным и продуктивным способом вырезать каждый символ из строки?

Например,

н = 5;

ул. = '1234A1234B1234C';

результат: "123412341234"

Это мой подход:

def delete_each_n(str, n)
  i = n

  str.length/n.times do
    str.slice!(i-1)
    i += (n - 1)
  end

  str
end


139
2
задан 11 февраля 2018 в 04:02 Источник Поделиться
Комментарии
4 ответа

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

Это 2.4.2 на MacBook Pro, и вы увидите, что Способ 4, используя bytesize и bytesliceи избегая regexp и mapЭто вдвое быстрее, чем следующий самый быстрый на длинных строк, и в пять раз быстрее на оригинальном примере.

2.4.2 :001 > def method1(string, n)
2.4.2 :002?> string.gsub(/.{#{n}}/){ |sub| sub.chop }
2.4.2 :003?> end
=> :method1
2.4.2 :004 >
2.4.2 :005 > def method2(string, index)
2.4.2 :006?> # Here I use a regular expression to split the string every n characters
2.4.2 :007 > substrings = string.split(%r{(.{#{index}})})
2.4.2 :008?> .reject(&:empty?) # And cut out any empty strings that appear
2.4.2 :009?>
2.4.2 :010 > # Then we can merge the substrings together, without the list character in each substring
2.4.2 :011 > substrings.map do |substring|
2.4.2 :012 > substring.length < index ? substring : substring[0..-2]
2.4.2 :013?> end.join
2.4.2 :014?> end
=> :method2
2.4.2 :015 >
2.4.2 :016 > def method3(string, index)
2.4.2 :017?> string.gsub(/(.{#{index-1}})./, '\\1')
2.4.2 :018?> end
=> :method3
2.4.2 :019 >
2.4.2 :020 > def method4(string, n)
2.4.2 :021?> length = n - 1
2.4.2 :022?> (0..(string.bytesize / n)).each_with_object("") do |x, new_string|
2.4.2 :023 > new_string << string.byteslice(x*n, length)
2.4.2 :024?> end
2.4.2 :025?> end
=> :method4
2.4.2 :026 >
2.4.2 :027 > require 'benchmark'
=> true
2.4.2 :028 >
2.4.2 :029 > runs = 100000
=> 100000
2.4.2 :030 > Benchmark.bm(7) do |x|
2.4.2 :031 > string = '1234A1234B1234C'
2.4.2 :032?> n = 5
2.4.2 :033?> x.report("method 0") { runs.times {}}
2.4.2 :034?> x.report("method 1") { runs.times {method1(string, n)}}
2.4.2 :035?> x.report("method 2") { runs.times {method2(string, n)}}
2.4.2 :036?> x.report("method 3") { runs.times {method3(string, n)}}
2.4.2 :037?> x.report("method 4") { runs.times {method4(string, n)}}
2.4.2 :038?> end ; ""
user system total real
method 0 0.000000 0.000000 0.000000 ( 0.003366)
method 1 0.570000 0.000000 0.570000 ( 0.572950)
method 2 0.670000 0.000000 0.670000 ( 0.666871)
method 3 0.750000 0.000000 0.750000 ( 0.763856)
method 4 0.120000 0.000000 0.120000 ( 0.118647)
=> ""
2.4.2 :039 >
2.4.2 :040 > runs = 50000
=> 50000
2.4.2 :041 > Benchmark.bm(7) do |x|
2.4.2 :042 > string = '1234A1234B1234C'*50
2.4.2 :043?> n = 2
2.4.2 :044?> x.report("method 0") { runs.times {}}
2.4.2 :045?> x.report("method 1") { runs.times {method1(string, n)}}
2.4.2 :046?> x.report("method 2") { runs.times {method2(string, n)}}
2.4.2 :047?> x.report("method 3") { runs.times {method3(string, n)}}
2.4.2 :048?> x.report("method 4") { runs.times {method4(string, n)}}
2.4.2 :049?> end ; ""
user system total real
method 0 0.000000 0.000000 0.000000 ( 0.001685)
method 1 7.110000 0.010000 7.120000 ( 7.131064)
method 2 11.450000 0.010000 11.460000 ( 11.475658)
method 3 9.640000 0.070000 9.710000 ( 9.721599)
method 4 3.750000 0.010000 3.760000 ( 3.758784)
=> ""
2.4.2 :050 >

1
ответ дан 13 февраля 2018 в 08:02 Источник Поделиться

Ваш код

У вас есть ошибка скрытую в коде!

1000/2.times {|i| puts i }

Вы, кажется, думаете, что этот код будет отображать 500 чисел между 0 и 499.
Это не так. Вместо этого, он отображает 0, 1и возвращает 500.

Вам нужно заменить str.length/n.times do С (str.length/n).times do.

Альтернатива

Вы можете использовать gsub искать подстроки, chop их и заменить их:

def delete_every_nth_char(string, n)
string.gsub(/.{#{n}}/){ |sub| sub.chop }
end

delete_every_nth_char('1234A1234B1234C', 5)
# "123412341234"
delete_every_nth_char('ABAB', 2)
# "AA"
delete_every_nth_char('ABA', 2)
# "AA"
delete_every_nth_char('ABA', 1)
# ""
delete_every_nth_char('ABA', 5)
# "ABA"

Он является кратким и, возможно, быстрее, чем разделение и объединение строк вручную.

3
ответ дан 11 февраля 2018 в 10:02 Источник Поделиться

Один из способов сделать это было бы разделить строку на подстроки, которые являются длина nзатем удалить последний элемент из каждой подстроки. Так, например:

def delete_each_n(string, index)
# Here I use a regular expression to split the string every n characters
substrings = string.split(%r{(.{#{index}})})
.reject(&:empty?) # And cut out any empty strings that appear

# Then we can merge the substrings together, without the list character in each substring
substrings.map do |substring|
substring.length < index ? substring : substring[0..-2]
end.join
end

2
ответ дан 11 февраля 2018 в 08:02 Источник Поделиться

Еще одним способом может быть:

 str.gsub(/(.{#{n-1}})./, '\\1')

0
ответ дан 12 февраля 2018 в 04:02 Источник Поделиться