如何根据ruby中的特定列表对结果进行排序

时间:2018-02-07 18:49:10

标签: ruby sorting

我有一个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。因此,只要保持动词的顺序是每个主题的预定义任意顺序,按“动词”或“主语”分组就可以了。

3 个答案:

答案 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]=[] }的说明,请参阅newHash::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,则可以保存一些代码/作品。