我有一个Ruby哈希,我希望在迭代之前对其进行过滤和排序。散列的结构具有依赖性,当我迭代时,我需要按特定顺序执行此操作。例如,使用以下哈希:
functionList = [
{"name":"CreateDog"},
{"name":"DeleteDog"},
{"name":"UpdateDog"},
{"name":"UpdateCat"},
{"name":"DeleteCat"},
{"name":"CreateCat"},
{"name":"FindAnimals"},
{"name":"Something"}
]
我想只过滤创建,更新或删除功能并循环,我喜欢这样:
validReg="^(Create|Update|Delete)"
functionList.select{|s| s["name"].match(validReg)}.map{|m| m["name"]}.each do |fun|
# invokeFunc(fun)
end
这将返回我想要的项目,但是以自然发生的顺序返回。但是,这些项目之间具有特定的关系 - 更新取决于更新时的创建和删除。所以我想以某种方式对functionList
的方式进行排序。我无法改变functionList
返回给我的方式,我需要在本地控制排序 - 例如.select
和.each
之间的某个位置。
我正在考虑按照["Create","Update","Delete"].each do |action| ....
方法做一些事情,想知道是否有任何“更好”的方法(没有循环和进行多次搜索) - 某种方式提供我自己的排序参考和调用在数组上排序可能吗?
澄清迭代所需的最终排序(.each
):
对于给定的主题,我首先需要所有Creates
。以下排序顺序很好:CreateDog,CreateCat,CreateX
然后是所有Updates
;或者也可以通过主题,例如排序顺序为CreateDog,UpdateDog,DeleteDog,CreateCat,UpdateCat,DeleteCat
。因此,只要保持动词的顺序是每个主题的预定义任意顺序,按“动词”或“主语”分组就可以了。
答案 0 :(得分:2)
为了避免多次搜索,请循环遍历列表一次,并创建一个由阶段键控的新哈希值,其值是该阶段的函数列表。然后你可以遍历阶段和列表。
这意味着你只需要遍历一次functionList,你就拥有了一个更容易分阶段处理的数据结构。
functionList = [
{"name":"CreateDog"},
{"name":"DeleteDog"},
{"name":"DeletedDog"},
{"name":"UpdateDog"},
{"name":"UpdateCat"},
{"name":"DeleteCat"},
{"name":"CreateCat"},
{"name":"FindAnimals"},
{"name":"Something"}
]
phases = ["create", "update", "delete"]
phaseRe = %r{^(Create|Update|Delete)[[:upper:]]}
phaseFunctions = Hash.new()
functionList.each do |func|
match = phaseRe.match(func[:name])
if match
(phaseFunctions[match[1].downcase] ||= []) << func
end
end
# In case any of the phases are empty.
# Can't set it earlier or everything will go into the default array.
phaseFunctions.default = []
phases.each do |phase|
phaseFunctions[phase].each do |func|
puts "#{phase} #{func}"
end
end
答案 1 :(得分:2)
按操作
ops = %w| Create Update Delete |
#=> ["Create", "Update", "Delete"]
functionList.each_with_object(Hash.new { |h,k| h[k]=[] }) do |g,h|
op = g[:name][/\A[[:upper:]][[:lower:]]+(?=[[:upper:]])/]
h[op] << g[:name] if ops.include?(op)
end.values_at(*ops).flatten
#=> ["CreateDog", "CreateCat", "UpdateDog", "UpdateCat", "DeleteDog", "DeleteCat"]
按主题
subs = %w| Dog Cat |
# => ["Dog", "Cat"]
functionList.each_with_object(Hash.new { |h,k| h[k]=[] }) do |g,h|
sub = g[:name][/(?<=[[:lower:]])[[:upper:]][[:lower:]]+\z/]
h[sub] << g[:name] if subs.include?(sub)
end.values_at(*subs).flatten
#=> ["CreateDog", "DeleteDog", "UpdateDog", "UpdateCat", "DeleteCat", "CreateCat"]
单一方法
当然可以将这些组合成一种方法。
def group_em(function_list, items, regex)
function_list.each_with_object(Hash.new { |h,k| h[k]=[] }) do |g,h|
item = g[:name][regex]
h[item] << g[:name] if items.include?(item)
end.values_at(*items).flatten
end
group_em(functionList, ops, /\A[[:upper:]][[:lower:]]+(?=[[:upper:]])/)
#=> ["CreateDog", "CreateCat", "UpdateDog", "UpdateCat", "DeleteDog", "DeleteCat"]
group_em(functionList, subs, /(?<=[[:lower:]])[[:upper:]][[:lower:]]+\z/)
# => ["CreateDog", "DeleteDog", "UpdateDog", "UpdateCat", "DeleteCat", "CreateCat"]
替代方法
可以使用Enumberable#group_by代替Hash::new,在这种情况下,方法如下。
def group_em(function_list, items, regex)
function_list.group_by { |g| g[:name][regex] }.
values_at(*items).
flatten.
map { |g| g[:name] }
end
对于操作案例,第一步是计算以下哈希值。
function_list.group_by { |g| g[:name][/\A[[:upper:]][[:lower:]]+(?=[[:upper:]])/] }
#=> {"Create"=>[{:name=>"CreateDog"}, {:name=>"CreateCat"}],
# "Delete"=>[{:name=>"DeleteDog"}, {:name=>"DeleteCat"}],
# "Update"=>[{:name=>"UpdateDog"}, {:name=>"UpdateCat"}],
# "Find"=>[{:name=>"FindAnimals"}],
# "Something"=>[{:name=>"Something"}]}
<强>解释强>
“按操作”案例中的步骤如下:
by_op = functionList.each_with_object(Hash.new { |h,k| h[k]=[] }) do |g,h|
op = g[:name][/\A[[:upper:]][[:lower:]]+(?=[[:upper:]])/]
h[op] << g[:name] if ops.include?(op)
end
#=> {"Create"=>["CreateDog", "CreateCat"],
# "Delete"=>["DeleteDog", "DeleteCat"],
# "Update"=>["UpdateDog", "UpdateCat"]}
arr = by_op.values_at(*ops)
#=> [["CreateDog", "CreateCat"], ["UpdateDog", "UpdateCat"], ["DeleteDog", "DeleteCat"]]
arr.flatten
#=> ["CreateDog", "CreateCat", "UpdateDog", "UpdateCat", "DeleteDog", "DeleteCat"]
by_op
的计算基本上是以下的紧凑版本。
by_op = {}
functionList.each do |g|
op = g[:name][/\A[[:upper:]][[:lower:]]+(?=[[:upper:]])/]
if ops.include?(op)
by_op[op] = [] unless by_op.key?(op)
by_op[op] << g[:name]
end
end
by_op
正则表达式显示“匹配字符串的开头(\A
)后跟一个大写字母,然后是一个或多个小写字母,后跟一个不属于匹配项的大写字母”。 (?=[[:upper:]])
是一个正向前瞻。
有关Hash.new { |h,k| h[k]=[] }
的说明,请参阅new
在Hash::new处理的案例的文档。
答案 2 :(得分:1)
在rxPermissions
.requestEachCombined(Manifest.permission.CAMERA,
Manifest.permission.ACCESS_FINE_LOCATION)
.subscribe(permission -> { // will emit 1 Permission object
if (permission.granted) {
// All permissions are granted !
} else if (permission.shouldShowRequestPermissionRationale)
// At least one denied permission without ask never again
} else {
// At least one denied permission with ask never again
// Need to go to the settings
}
});
之前sort_by { |s| 'CUD'.index(s[0]) }
。
或each
。
或sort_by { |s| s[1] }.reverse
。
对后两者不太认真。但我认为第一个是好的。
顺便说一下,如果sort_by { |s| s[3] + s[0] }
之前map
select
,则可以保存一些代码/作品。