Каков наилучший способ нарезать строку в куски определенной длины в Ruby?
Я искал элегантный и эффективный способ разбить строку на подстроки заданной длины в Ruby.
Пока что лучшее, что я мог придумать, это:
def chunk(string, size)
(0..(string.length-1)/size).map{|i|string[i*size,size]}
end
>> chunk("abcdef",3)
=> ["abc", "def"]
>> chunk("abcde",3)
=> ["abc", "de"]
>> chunk("abc",3)
=> ["abc"]
>> chunk("ab",3)
=> ["ab"]
>> chunk("",3)
=> []
Возможно, вы захотите, чтобы chunk("", n)
возвращал [""]
вместо []
. Если так, просто добавьте это как первую строку метода:
return [""] if string.empty?
Вы бы порекомендовали какое-нибудь лучшее решение?
редактировать
Спасибо Джереми Рутену за это элегантное и эффективное решение: [edit: НЕ эффективно!]
def chunk(string, size)
string.scan(/.{1,#{size}}/)
end
редактировать
Решение string.scan занимает около 60 секунд, чтобы нарезать 512 тыс. Кусков на 1 тыс. Кусков 10000 раз по сравнению с исходным решением на основе срезов, которое занимает всего 2,4 секунды.
Ответы
Ответ 1
Используйте String#scan
:
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,4}/)
=> ["abcd", "efgh", "ijkl", "mnop", "qrst", "uvwx", "yz"]
>> 'abcdefghijklmnopqrstuvwxyz'.scan(/.{1,3}/)
=> ["abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz"]
Ответ 2
Вот еще один способ сделать это:
"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }
= > [ "abc", "def", "ghi", "jkl", "mno", "pqr", "stu", "vwx", "yz" ]
Ответ 3
Я думаю, что это наиболее эффективное решение, если вы знаете, что ваша строка кратна размеру блока
def chunk(string, size)
(string.length / size).times.collect { |i| string[i * size, size] }
end
и для частей
def parts(string, count)
size = string.length / count
count.times.collect { |i| string[i * size, size] }
end
Ответ 4
test.split(/(...)/).reject {|v| v.empty?}
Отклонение необходимо, потому что оно в противном случае включает пробел между наборами. Мое регулярное выражение не совсем подходит для того, чтобы понять, как это исправить прямо с моей головы.
Ответ 5
Вот еще одно решение для немного другого случая, когда обрабатываются большие строки, и нет необходимости хранить все порции за раз. Таким образом, он хранит один блок за раз и работает намного быстрее, чем нарезка строк:
io = StringIO.new(string)
until io.eof?
chunk = io.read(chunk_size)
do_something(chunk)
end
Ответ 6
Лучшее решение, которое учитывает последнюю часть строки, которая может быть меньше размера чанка:
def chunk(inStr, sz)
return [inStr] if inStr.length < sz
m = inStr.length % sz # this is the last part of the string
partial = (inStr.length / sz).times.collect { |i| inStr[i * sz, sz] }
partial << inStr[-m..-1] if (m % sz != 0) # add the last part
partial
end
Ответ 7
Есть ли еще некоторые ограничения, которые вы имеете в виду? В противном случае у меня было бы ужасно искушение сделать что-то простое, например
[0..10].each {
str[(i*w),w]
}