97

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 秒しかかかりません。

4

9 に答える 9

168

使用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"]
于 2009-04-16T01:26:05.413 に答える
21

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

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

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

于 2011-02-04T20:04:59.770 に答える
6

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

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
于 2015-07-26T14:00:08.720 に答える
5

約 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
于 2020-02-20T23:17:31.453 に答える
4

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

io = StringIO.new(string)
until io.eof?
  chunk = io.read(chunk_size)
  do_something(chunk)
end
于 2018-09-20T09:28:42.927 に答える
1
test.split(/(...)/).reject {|v| v.empty?}

それ以外の場合はセット間の空白スペースが含まれるため、拒否が必要です。私の正規表現-fuは、頭のてっぺんからそれを修正する方法を理解するまでには至っていません。

于 2009-04-16T01:20:56.657 に答える
0

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

[0..10].each {
   str[(i*w),w]
}
于 2009-04-16T01:15:04.520 に答える