mr_muscle
mr_muscle

Reputation: 2900

Ruby exclude specific data from array of hashes

I've got response which hash and array of hashes:

"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"}},
  ]

What I need is to pull the name for each hash['actors'] and convert it to the email address. The thing is I need to skip names which are defined as EXCLUDED_NAMES

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

private_constant :DEFAULT_EXCLUDED_NAMES

I was trying to something like below but still get all 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

Upvotes: 0

Views: 867

Answers (4)

Surya
Surya

Reputation: 16012

If dev_role['actors'] is this:

  [
    {"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"}},
  ]

then it is certain that user in each block would be a Hash object:

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

So, doing user["name"], should produce: "john.doe".

Now, that we have an exclusion list EXCLUDED_NAMES we could use include? like so on it:

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

So, all you need is a small change in your code to fix the condition:

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

There is one problem though, the user.delete would not work as it expects an argument that is supposed to be a key to the hash object.

This can be fixed through by using reject or select(changing to reject as it reads better):

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

The nature of the method seems to be returning an array/list, so I would insist that the name of such methods should be plural: setup_emails.

Upvotes: 1

Yashvi Patel
Yashvi Patel

Reputation: 33

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

Upvotes: 0

3limin4t0r
3limin4t0r

Reputation: 21130

I'd create a lookup hash based upon the the actor name. Then retrieve the values that are not in EXCLUDED_NAMES.

When actors can contain duplicate names:

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

When actors can't contain duplicate names:

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

Then:

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

You could also solve this with an Array#reject/Array#map combination:

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

The above might be slower when using a large EXCLUDED_NAMES array.

Upvotes: 0

romnoks
romnoks

Reputation: 131

You can get an array of valid emails with:

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

Array will only contain '[email protected]'

Upvotes: 2

Related Questions