2

nilsで初期化された配列を、空のセグメントと連続する数値を含むセグメントに分けたい状況があります。

これに対するエレガントなソリューションを提供する の高階chunk関数を見つけました。Array

<< [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }.each { |e| p e }

>> [false, [nil, nil]]
>> [true, [1, 2]]
>> [false, [nil]]
>> [true, [3]]

ただし、各チャンクの元の配列への開始インデックスも出力に含めたいとします。つまり、上記の出力を次のように拡張します。

>> [false, 0, [nil, nil]]
>> [true, 2, [1, 2]]
>> [false, 4, [nil]]
>> [true, 5, [3]]

上記のチャンク スニペットの表現力を保持するこれを取得するための解決策はありますか?

前もって感謝します。

4

2 に答える 2

5

機能的なモジュラー アプローチ: 入力配列チャンクにインデックスを付け、目的の出力 O(n) にマップします。

data = xs.each_with_index.chunk { |x, i| !x.nil? }.map do |match, pairs| 
  [match, pairs.first[1], pairs.map(&:first)] 
end
#=> [[false, 0, [nil, nil]], [true, 2, [1, 2]], [false, 4, [nil]], [true, 5, [3]]]
于 2013-01-31T19:36:15.893 に答える
1

出力をウォークスルーして、chunk開始インデックスを自分で追跡できます。各チャンクの長さだけインクリメントするだけです。これが私の簡単な試みです。

chunked = [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }

_, chunks_with_embedded_index = chunked.each_with_object([0, []]) do |(k, chunk), memo|
  memo[1] << [k, memo[0], chunk]
  memo[0] += chunk.length
end

chunks_with_embedded_index.each {|c| p c }
# >> [false, 0, [nil, nil]]
# >> [true, 2, [1, 2]]
# >> [false, 4, [nil]]
# >> [true, 5, [3]]

最後のインデックスの一時変数を完全なローカル変数に抽出し、実装をややクリーンにすることができます。

chunked = [nil,nil,1,2,nil,3].chunk { |e| !e.nil? }

last_index = 0
chunks_with_embedded_index = chunked.reduce([]) do |memo, (k, chunk)|
  memo << [k, last_index, chunk]
  last_index += chunk.length
  memo
end

chunks_with_embedded_index.each {|c| p c }
# >> [false, 0, [nil, nil]]
# >> [true, 2, [1, 2]]
# >> [false, 4, [nil]]
# >> [true, 5, [3]]
于 2013-01-31T19:35:31.463 に答える