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?
더 나은 솔루션을 추천 하시겠습니까?
편집하다
이 우아하고 효율적인 솔루션에 대해 Jeremy Ruten에게 감사드립니다. [편집 : 비효율적입니다!]
def chunk(string, size)
string.scan(/.{1,#{size}}/)
end
편집하다
string.scan 솔루션은 2.4 초 밖에 걸리지 않는 원래 슬라이스 기반 솔루션과 비교하여 512k를 1k 청크로 10000 번 자르는 데 약 60 초가 걸립니다.
답변
사용 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"]
답변
다른 방법은 다음과 같습니다.
"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }
=> [ “abc”, “def”, “ghi”, “jkl”, “mno”, “pqr”, “stu”, “vwx”, “yz”]
답변
문자열이 청크 크기의 배수라는 것을 알고 있다면 이것이 가장 효율적인 솔루션이라고 생각합니다.
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
답변
큰 문자열을 처리하고 한 번에 모든 청크를 저장할 필요가없는 경우 약간 다른 경우에 대한 또 다른 솔루션이 있습니다. 이런 식으로 한 번에 하나의 청크를 저장하고 문자열을 분할하는 것보다 훨씬 빠르게 수행합니다.
io = StringIO.new(string)
until io.eof?
chunk = io.read(chunk_size)
do_something(chunk)
end
답변
약 593MB 데이터를 18991 32KB 조각으로 자르는 작은 테스트를했습니다. ctrl + C를 누르기 전에 100 % CPU를 사용하여 슬라이스 + 맵 버전을 15 분 이상 실행했습니다. String # unpack을 사용하는이 버전은 3.6 초 만에 완료되었습니다.
def chunk(string, size)
string.unpack("a#{size}" * (string.size/size.to_f).ceil)
end
답변
test.split(/(...)/).reject {|v| v.empty?}
그렇지 않으면 세트 사이에 공백이 포함되므로 거부가 필요합니다. 내 regex-fu는 내 머리 꼭대기에서 바로 수정하는 방법을 보지 못했습니다.
답변
청크 크기보다 작을 수있는 문자열의 마지막 부분을 고려하는 더 나은 솔루션 :
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