[ruby] 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?

더 나은 솔루션을 추천 하시겠습니까?

편집하다

이 우아하고 효율적인 솔루션에 대해 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