简体   繁体   English

搜索一个Ruby数组

[英]Searching a Ruby Array

I am building a Ruby array for the purposes of a grouped select box as follows 我正在为如下的分组选择框构建一个Ruby数组

def self.actions
  actions = []
  status_actions = []
  priority_actions = []
  user_actions = []

for status in Choice.ticket_statuses
  status_actions << ["Set ticket status to [#{status.name}]","ticket.status_id = #{status.id}"]
end

for priority in Choice.ticket_priorities
  priority_actions << ["Set ticket priority to [#{priority.name}]","ticket.priority_id = #{priority.id}"]
end

for user in User.all
  user_actions << ["Set owner to [#{user.name}]","ticket.user_id = #{user.id}"]
end

actions << ["Status", status_actions]
actions << ["Priority", priority_actions]
actions << ["User", user_actions]

return actions
end

Which gives me an array that looks like this: 这给了我一个看起来像这样的数组:

[
 ["Status", 
  [["Set ticket status to [Closed]", "ticket.status_id = 7"], 
   ["Set ticket status to [Open]", "ticket.status_id = 6"], 
   ["Set ticket status to [Waiting 3rd Party]", "ticket.status_id = 8"], 
   ["Set ticket status to [Waiting on Client]", "ticket.status_id = 9"]]
  ], 
 ["Priority", 
  [["Set ticket priority to [High]", "ticket.priority_id = 5"], 
  ["Set ticket priority to [Low]", "ticket.priority_id = 3"], 
  ["Set ticket priority to [Medium]", "ticket.priority_id = 4"]]
 ], 
["User", 
 [["Set owner to [UNLOCK-DEV]", "ticket.user_id = 1"]]
 ]
]

Now I need a way to search this array for one of the values like "ticket.status_id = 7" and get the name returned like "Set ticket status to [Closed]". 现在,我需要一种方法在此数组中搜索值之一,例如“ ticket.status_id = 7”,并获得返回的名称,例如“将票证状态设置为[已关闭]”。

eg 例如

def return_name(value)
  TicketAction.actions.collect(&:last).first.select { |action| action[1] == value }.first.first
end

so I can call like 所以我可以打电话给

return_name("ticket.status_id = 7")
> "Set ticket status to [Closed]"

My current return_name function (despite being very messy) is only searching the "status" part of the array. 我当前的return_name函数(尽管非常混乱)仅在搜索数组的“状态”部分。

You can use recursion: 您可以使用递归:

def return_name(arr, value)
  if arr.is_a? Array
    return arr.first if value == arr.last
    arr.map { |i| return_name(i, value) }.compact.first
  end
end

return_name(arr, 'ticket.priority_id = 4')
# => "Set ticket priority to [Medium]" 

What this code does is: 该代码的作用是:

  • return nil unless arr is an Array . 除非arr是一个Array否则返回nil
  • It returns the first value of the array if the last value equals what you are looking for 如果最后一个值等于您要查找的值,它将返回数组的第一个值
  • otherwise, it recurses on all its children to find the first which has a match. 否则,它将递归所有子项,以找到第一个具有匹配项的子项。

"Recurse" means calls itself for all it items - it checks whether any of its children can answer your question by asking them the same question. “递归”是指对其所有项目进行自我调用-它检查其子级是否可以通过询问相同的问题来回答您的问题。

One approach you could take would be to convert the array to a string and then search the string with a regex. 您可以采用的一种方法是将数组转换为字符串,然后使用正则表达式搜索字符串。

Code

def return_name(arr, str)
  arr.to_s[/\"(Set ticket [a-z]+ to \[[\w\s]+\])\",\s+\"#{str}\"/,1]
end

Examples 例子

arr = [
  ["Status", 
    [["Set ticket status to [Closed]", "ticket.status_id = 7"], 
     ["Set ticket status to [Open]", "ticket.status_id = 6"], 
     ["Set ticket status to [Waiting 3rd Party]", "ticket.status_id = 8"], 
     ["Set ticket status to [Waiting on Client]", "ticket.status_id = 9"]
    ]
  ], 
  ["Priority", 
    [["Set ticket priority to [High]", "ticket.priority_id = 5"], 
     ["Set ticket priority to [Low]", "ticket.priority_id = 3"], 
     ["Set ticket priority to [Medium]", "ticket.priority_id = 4"]]
  ], 
  ["User", 
    [["Set owner to [UNLOCK-DEV]", "ticket.user_id = 1"]]
  ]
]

return_name(arr, "ticket.status_id = 7")
  #=>  "Set ticket status to [Closed]"
return_name(arr, "ticket.status_id = 6")
  #=> "Set ticket status to [Open]"
return_name(arr, "ticket.status_id = 8")
  #=> "Set ticket status to [Waiting 3rd Party]"
return_name(arr, "ticket.status_id = 9")
  #=> "Set ticket status to [Waiting on Client]"

return_name(arr, "ticket.priority_id = 5")
  #=> "Set ticket priority to [High]"
return_name(arr, "ticket.priority_id = 3")
  #=> "Set ticket priority to [Low]"
return_name(arr, "ticket.priority_id = 4")
  #=> "Set ticket priority to [Medium]"

Want them all? 想要他们全部吗?

r = /(Set ticket [a-z]+ to \[[\w\s]+\])(?:\",\s+\")(ticket\.[a-z]+_id = \d+)/
arr.to_s.scan(r).map(&:reverse).to_h
  #=> {"ticket.status_id = 7"  =>"Set ticket status to [Closed]",
  #    "ticket.status_id = 6"  =>"Set ticket status to [Open]",
  #    "ticket.status_id = 8"  =>"Set ticket status to [Waiting 3rd Party]",
  #    "ticket.status_id = 9"  =>"Set ticket status to [Waiting on Client]",
  #    "ticket.priority_id = 5"=>"Set ticket priority to [High]",
  #    "ticket.priority_id = 3"=>"Set ticket priority to [Low]",
  #    "ticket.priority_id = 4"=>"Set ticket priority to [Medium]"}

Here are some no-recursive ways of doing it: 以下是一些无递归的方法:

def return_name(search_term)
  # a flattened array will alywas have the value you are searching for jsut before the search term, so just get the index before that.
  temp_array = @data.flatten
  ix = temp_array.index(search_term)
  ix ? temp_array[ix-1] : nil
end

  # some more Ruby magic.
p @data.map(&:last).flatten(1).rassoc("ticket.user_id = 1") #=> ["Set owner to [UNLOCK-DEV]", "ticket.user_id = 1"]

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM