假设我有这样一个数组
a = [
{key: "cat", value: 1},
{key: "dog", value: 2},
{key: "mouse", value: 5},
{key: "rat", value: 3},
{key: "cat", value: 5},
{key: "rat", value: 2},
{key: "cat", value: 1},
{key: "cat", value: 1}
]
假设我有这个数组,并且只想获取"cat"的最新值。
我知道如何选择所有的
a.select do |e|
e[:key] == "cat"
end
但是我正在寻找一种方法来获取最后3个
的选择期望的结果是
[
{key: "cat", value: 5},
{key: "cat", value: 1},
{key: "cat", value: 1}
]
谢谢!
在@Stefan提出的问题的评论中:
a.select { |e| e[:key] == "cat" }.last(3)
如果a
不是太大,您可能应该使用它。然而,如果a
很大,特别是如果它包含许多元素(哈希值)h
对应h[:key] #=> "cat"
,那么从数组的末尾向后迭代并在找到h[:key] #=> "cat"
对应的三个元素h
时终止("短路")可能会更有效。这也避免了构造一个可能很大的临时数组(a.select { |e| e[:key] == "cat" }
)。
方法如下:
a.reverse_each.with_object([]) do |h,arr|
arr.insert(0,h) if h[:key] == "cat"
break arr if arr.size == 3
end
#=> [{:key=>"cat", :value=>5},
# {:key=>"cat", :value=>1},
# {:key=>"cat", :value=>1}]
参见array# reverse_each, Enumerator#with_object和array# insert。注意,由于reverse_each
和with_object
都返回枚举数,因此将它们链接起来也会生成一个枚举数:
a.reverse_each.with_object([])
#=> #<Enumerator: #<Enumerator: [{:key=>"cat", :value=>1},
# ...
# {:key=>"cat", :value=>1}]:reverse_each>:with_object([])>
用
代替块计算可能会稍微快一点arr << h if h[:key] == "cat"
break arr.reverse if arr.size == 3
如果a
包含较少的元素h
,而h[:key] #=> "cat"
将返回一个数组arr
,而arr.size < 3
。因此有必要确认返回的数组包含三个元素。
当使用@Stefan建议的代码时,也必须执行此检查,例如
a.select { |e| e[:key] == "cat" }.last(99)
#=> [{:key=>"cat", :value=>1},
# {:key=>"cat", :value=>5},
# {:key=>"cat", :value=>1},
# {:key=>"cat", :value=>1}]