@Steenslagと@Stefanは、元の回答と同じ改善(示唆は異なっていますが)を提案しました。私はその改善を組み込むために私の答えを編集しました。
コード
def doit(arr, n)
h = Hash.new(0)
arr.select { |e| n >= h[e] += 1 }
end
例
arr = [1,2,3,1,2,1,2,3]
n = 2
doit arr, n
#=> [1, 2, 3, 1, 2, 3]
説明
例でarr
とn
の値に対して実行されるステップをf通りでありますollows。
h = Hash.new(0)
Hash::newの形式です。これはデフォルト値(ここではゼロ)をとります。つまり、すべてはh
がキーk
持っていない上で定義されている場合、デフォルト値が返されることです。
h['cat'] #=> 0
これは、ハッシュは変更されません。 h[:a] = 1
と書くと(h=>{:a=>1}
)、h[:a]
はh
に:a
のキーがあるので、1
を返します。続いて、
enum = arr.reject
# => #<Enumerator: [1, 2, 3, 1, 2, 1, 2, 3]:reject>
最初の値はenum
によって生成されたブロックに渡され、ブロック変数は、その値が割り当てられています。
e = enum.next
#=> 1
ブロック演算について今
h #=> { 1=>1 }
とarr
の最初の要素が選択された
2 >= h[1]
#=> true
のでそう
h[e] += 1
#=> h[e] = h[e] + 1
# h[e] = 0 + 1 = 1
行われます。
式h[1] = h[1] + 1
については、注意すべき点が2つあります。まず、h
には1
というキーがないため、等価の右側にあるh[1]
はデフォルト値の0を返します。次に、デフォルト値は、Hash#[]=(等号の左側)ではなく、Hash#[]というメソッドで使用されます。
enum
という2番目の値がブロックに渡され、同様の計算が実行されます。
e = enum.next
#=> 2
h[e] += 1
#=> h[2] = h[2] + 1
# h[2] = 0 + 1
h #=> {1=>1, 2=>1}
2 >= h[2]
#=> true
だからarr
の第二の要素は、選択されます。この時点
h = { 1=>2, 2=>2, 3=>1 }
で
enum.next
#=> 3
enum.next
#=> 1
enum.next
#=> 2
とブロックがenum
によって生成された第1 5
要素ごとにtruthy値を返しました:さんはenum
によって生成された次の3つの要素をスキップしてみましょう。
次に、
e = enum.next
#=> 1
h[e] += 1
#=> h[1] = h[1] + 1
# h[1] = 2 + 1
h #=> {1=>3, 2=>2, 3=>1}
2 >= h[1]
#=> 2 >= 3 => false
ので、この値は、1
が選択されていません。残りの計算は似ています。
'arr.select {| e | (h [e] + = 1)<= n} ' – steenslag
' arr.reject {| e | n
Stefan
多くのおかげで、@steenslagと... –