ruby 如何过滤散列数组以仅获取另一个数组中的键?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/9538090/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How can I filter an array of hashes to get only the keys in another array?
提问by pedalpete
I'm trying get a subset of keys for each hash in an array.
我正在尝试为数组中的每个散列获取一个键子集。
The hashes are actually much larger, but I figured this is easier to understand:
散列实际上要大得多,但我认为这更容易理解:
[
{
id:2,
start: "3:30",
break: 30,
num_attendees: 14
},
{
id: 3,
start: "3: 40",
break: 40,
num_attendees: 4
},
{
id: 4,
start: "4: 40",
break: 10,
num_attendees: 40
}
]
I want to get only the idand startvalues.
我只想得到id和start值。
I've tried:
我试过了:
return_keys = ['id','start']
return_array = events.select{|key,val| key.to_s.in? return_keys}
but this returns an empty array.
但这会返回一个空数组。
回答by Andrew Marshall
This should do what you want:
这应该做你想做的:
events.map do |hash|
hash.select do |key, value|
[:id, :start].include? key
end
end
Potentially faster (but somewhat less pretty) solution:
可能更快(但不太漂亮)的解决方案:
events.map do |hash|
{ id: hash[:id], start: hash[:start] }
end
If you need return_keysto be dynamic:
如果您需要return_keys动态:
return_keys = [:id, :start]
events.map do |hash|
{}.tap do |new_hash|
return_keys.each do |key|
new_hash[key] = hash[key]
end
end
end
Note that, in your code, selectpicks out elements from the array, since that's what you called it on, but doesn't change the hashes contained within the array.
请注意,在您的代码中,select从array 中挑选元素,因为这是您调用它的原因,但不会更改包含在数组中的哈希值。
If you're concerned about performance, I've benchmarked all of the solutions listed here (code):
如果您担心性能,我已经对此处列出的所有解决方案进行了基准测试(代码):
user system total real
amarshall 1 0.140000 0.000000 0.140000 ( 0.140316)
amarshall 2 0.060000 0.000000 0.060000 ( 0.066409)
amarshall 3 0.100000 0.000000 0.100000 ( 0.101469)
tadman 1 0.140000 0.010000 0.150000 ( 0.145489)
tadman 2 0.110000 0.000000 0.110000 ( 0.111838)
mu 0.130000 0.000000 0.130000 ( 0.128688)
回答by mu is too short
If you happen to be using Rails (or don't mind pulling in all or part of ActiveSupport) then you could use Hash#slice:
如果您碰巧正在使用 Rails(或者不介意使用全部或部分 ActiveSupport),那么您可以使用Hash#slice:
return_array = events.map { |h| h.slice(:id, :start) }
Hash#slicedoes some extra work under the covers but it is probably fast enough that you won't notice it for small hashes and the clarity is quite nice.
Hash#slice在幕后做了一些额外的工作,但它可能足够快,以至于您不会注意到小哈希值,并且清晰度非常好。
回答by tadman
A better solution is to use a hash as your index instead of doing a linear array lookup for each key:
更好的解决方案是使用散列作为索引,而不是对每个键进行线性数组查找:
events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]
return_keys = [ :id, :start ]
# Compute a quick hash to extract the right values: { key => true }
key_index = Hash[return_keys.collect { |key| [ key, true ] }]
return_array = events.collect do |event|
event.select do |key, value|
key_index[key]
end
end
# => [{:id=>2, :start=>"3:30"}, {:id=>3, :start=>"3:40"}, {:id=>4, :start=>"4:40"}]
I've adjusted this to use symbols as the key names to match your definition of events.
我已经对此进行了调整,以使用符号作为键名来匹配您对events.
This can be further improved by using the return_keysas a direct driver:
这可以通过将return_keys用作直接驱动程序来进一步改进:
events = [{id:2, start:"3:30",break:30,num_attendees:14},{id:3, start:"3:40",break:40,num_attendees:4},{id:4, start:"4:40",break:10,num_attendees:40}]
return_keys = [ :id, :start ]
return_array = events.collect do |event|
Hash[
return_keys.collect do |key|
[ key, event[key] ]
end
]
end
The result is the same. If the subset you're extracting tends to be much smaller than the original, this might be the best approach.
结果是一样的。如果您提取的子集往往比原始子集小得多,这可能是最好的方法。
回答by Cary Swoveland
Considering that efficiency appears to be a concern, I would suggest the following.
考虑到效率似乎是一个问题,我建议如下。
Code
代码
require 'set'
def keep_keys(arr, keeper_keys)
keepers = keeper_keys.to_set
arr.map { |h| h.select { |k,_| keepers.include?(k) } }
end
This uses Hash#select, which, unlike Enumerable#select, returns a hash. I've converted keeper_keysto a set for fast lookups.
这使用Hash#select,与Enumerable#select不同,它返回一个哈希值。我已转换keeper_keys为一组以进行快速查找。
Examples
例子
arr = [{ id:2, start: "3:30", break: 30 },
{ id: 3, break: 40, num_attendees: 4 },
{ break: 10, num_attendees: 40 }]
keep_keys arr, [:id, :start]
#=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}]
keep_keys arr, [:start, :break]
#=> [{:start=>"3:30", :break=>30}, {:break=>40}, {:break=>10}]
keep_keys arr, [:id, :start, :cat]
#=> [{:id=>2, :start=>"3:30"}, {:id=>3}, {}]
keep_keys arr, [:start]
#=> [{:start=>"3:30"}, {}, {}]
keep_keys arr, [:cat, :dog]

