【问题标题】:Ruby exclude specific data from array of hashesRuby 从哈希数组中排除特定数据
【发布时间】:2020-02-04 11:15:48
【问题描述】:

我得到了哪个哈希和哈希数组的响应:

"id"=>67547,
 "description"=>"project",
 "actors"=>
  [
    {"id"=>123,
    "displayName"=>"John Doe",
    "type"=>"atlassian-user-role-actor",
    "name"=>"john.doe",
    "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>456,
     "displayName"=>"Chris Sth",
     "type"=>"atlassian-user-role-actor",
     "name"=>"chris.sth",
     "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>789,
     "displayName"=>"Testing Name",
     "type"=>"atlassian-user-role-actor",
     "name"=>"testing.name",
     "actorUser"=>{"accountId"=>"some_id"}},
  ]

我需要提取每个hash['actors'] 的名称并将其转换为电子邮件地址。问题是我需要跳过定义为 EXCLUDED_NAMES

的名称
EXCLUDED_NAMES = %w[
  chris.sth
  removed1258986304
  john.doe
  other.names
].freeze

private_constant :DEFAULT_EXCLUDED_NAMES

我正在尝试类似下面的内容,但仍然得到所有名称:

def setup_email
  dev_role['actors'].map do |user|
    if user.include?(EXCLUDED_NAMES)
      user.delete
    else
      "#{user['name']}@example.com"
    end
  end
end

【问题讨论】:

  • 所有答案(@3limin4t0r 答案的一部分除外)都包含EXCLUDED_NAMES.include?(user["name"])。如果EXCLUDED_NAMES.include?(user["name"]) 很大,您可以通过使用集合来加快速度,该集合的查找时间很快,与哈希中的键查找相当:require 'set'; ex = EXCLUDED_NAMES.to_set,然后将代码中的EXCLUDED_NAMES 替换为ex。跨度>

标签: ruby ruby-hash


【解决方案1】:

您可以获得一组有效的电子邮件:

emails = dev_role['actors'].map do |user|
  "#{user['name']}@example.com" unless EXCLUDED_NAMES.include?(user['name'])
end

数组将只包含 'testing.name@example.com'

【讨论】:

  • "数组将只包含 'testing.name@example.com'"nil
  • 一个小建议:格式化你的答案,这样读者就不需要水平滚动来阅读它们(在这里,可能在unless 之后打破倒数第二行)。此外,emails = 是一种不必要的干扰。
【解决方案2】:

如果dev_role['actors'] 是这样的:

  [
    {"id"=>123,
    "displayName"=>"John Doe",
    "type"=>"atlassian-user-role-actor",
    "name"=>"john.doe",
    "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>456,
     "displayName"=>"Chris Sth",
     "type"=>"atlassian-user-role-actor",
     "name"=>"chris.sth",
     "actorUser"=>{"accountId"=>"some_id"}},
   {"id"=>789,
     "displayName"=>"Testing Name",
     "type"=>"atlassian-user-role-actor",
     "name"=>"testing.name",
     "actorUser"=>{"accountId"=>"some_id"}},
  ]

那么可以确定each 块中的user 将是Hash 对象:

{
  "id"=>123,
  "displayName"=>"John Doe",
  "type"=>"atlassian-user-role-actor",
  "name"=>"john.doe",
  "actorUser"=>{"accountId"=>"some_id"}
}

所以,执行user["name"],应该产生:"john.doe"

现在,我们有一个排除列表EXCLUDED_NAMES,我们可以像这样使用include?

EXCLUDED_NAMES.include?(user["name"])
=> # true if the name is in the EXCLUDED_NAMES

因此,您只需要对代码进行一些小改动即可解决此问题:

def setup_email
  dev_role['actors'].map do |user|
    if EXCLUDED_NAMES.include?(user["name"])
      user.delete
    else
      "#{user['name']}@example.com"
    end
  end
end

但有一个问题,user.delete 无法工作,因为它需要一个应该是哈希对象键的参数。

这可以通过使用rejectselect 来解决(更改为reject,因为它读起来更好):

def setup_email
  dev_role['actors'].reject do |user|
    EXCLUDED_NAMES.include?(user["name"])
  end.map{ |user| user["name"] }
end

该方法的本质似乎是返回一个数组/列表,所以我坚持认为这些方法的名称应该是复数:setup_emails

【讨论】:

  • 感谢您的澄清,一件事 - rubocop 建议我使用 reject 而不是 select
  • 两者都可以。
  • ...但是reject 读起来更好,因为 if 避免了否定并且还保存了一个操作。
  • 您的解释令人困惑。你说,“所以,你所需要的只是代码中的一个小改动。”,然后是一个修改 OP 给出的代码的代码块,大概包含纠正它所需的“小改动”。然而,你接着说,你刚刚给出的代码实际上并没有纠正它:“我不确定user.delete 是否会起作用,因为它期望一个应该是键的参数。”你是not“不确定”;你很清楚user.delete 会引发异常,因为你给出的原因,所以说出来。
  • "但是 reject..." - 是的,你是对的,我的意思是两者都有效。修复条件的代码更改很小,当然,删除是行不通的,所以必须单独指出 - 这与帖子中提到的事情无关。如果担心的话,通过删除不确定的部分来更新帖子?
【解决方案3】:

我会根据演员名称创建一个查找哈希。然后检索不在EXCLUDED_NAMES 中的值。

当演员可以包含重复的名字时:

actors = dev_role['actors'].group_by { |actor| actor['name'] }
actors = actors.values_at(*actors.keys - EXCLUDED_NAMES).flatten(1)

当演员不能包含重复的名字时:

actors = dev_role['actors'].to_h { |actor| [actor['name'], actor] }
actors = actors.values_at(*actors.keys - EXCLUDED_NAMES)

然后:

emails = actors.map { |actor| "#{actor['name']}@example.com" }

您也可以使用Array#reject/Array#map 组合来解决此问题:

emails = dev_role['actors']
         .reject { |actor| EXCLUDED_NAMES.include?(actor['name']) }
         .map { |actor| "#{actor['name']}@example.com" }

使用大型 EXCLUDED_NAMES 数组时,上述操作可能会变慢。

【讨论】:

    【解决方案4】:
    dev_role=dev_role.to_hash
    actors=dev_role["actors"]
    for each_actor in actors
        if EXCLUDED_NAMES.include?(each_actor["name"])==false
            p "#{each_actor['name']}@example.com"
        end
    end
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2015-11-13
      • 1970-01-01
      • 2018-11-15
      • 1970-01-01
      • 2012-04-08
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多