web-dev-qa-db-ja.com

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ソリューションは、512kを1kのチャンクに10000回刻むのに約60秒かかりますが、元のスライスベースのソリューションは2.4秒しかかかりません。

84
MiniQuark

使用する 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"]
150
Jeremy Ruten

これを行う別の方法を次に示します。

"abcdefghijklmnopqrstuvwxyz".chars.to_a.each_slice(3).to_a.map {|s| s.to_s }

=> ["abc"、 "def"、 "ghi"、 "jkl"、 "mno"、 "pqr"、 "stu"、 "vwx"、 "yz"]

17
Jason

文字列がチャンクサイズの倍数であることがわかっている場合、これが最も効率的なソリューションだと思います

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
6
davispuh

チャンクサイズよりも小さい文字列の最後の部分を考慮に入れたより良いソリューション:

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
1
kirkytullins

大きな文字列を処理し、一度にすべてのチャンクを保存する必要がない場合の、わずかに異なるケースの別のソリューションを次に示します。このようにして、一度に1つのチャンクを格納し、文字列をスライスするよりもはるかに高速に実行します。

io = StringIO.new(string)
until io.eof?
  chunk = io.read(chunk_size)
  do_something(chunk)
end
1
prcu
test.split(/(...)/).reject {|v| v.empty?}

それ以外の場合はセット間に空白スペースが含まれるため、拒否が必要です。私の正規表現-フーは、私の頭の上からすぐにそれを修正する方法を見ることはできません。

1
Chuck

あなたが考えている他の制約はありますか?そうでなければ、私は次のような単純なことをやろうと思うでしょう

[0..10].each {
   str[(i*w),w]
}
0
Charlie Martin