dax
dax

Reputation: 10997

Determine if neighbors exist?

I have a reference hash of all possible ranks that looks like this:

hash = {
  bronze: 0,
  silver: 1,
  gold: 2,
  platinum: 3,
  diamond: 4
}

I get a given rank, and an array of other existing ranks, and I need to determine if 'neighbors' exist for the given rank. I'll try an example:

given_rank = 'gold'  
existing_ranks =  ['silver', 'platinum']

This should return true - silver is directly beneath gold and platinum is directly above - both neighbors are present.

given_rank = 'gold'  
existing_ranks =  ['silver', 'diamond']

This should return false - platinum is missing on the upper side

Here's what I have now:

user_rank = hash[given_rank]
higher = hash.invert[user_rank + 1]
lower = hash.invert[user_rank - 1]

if existing_ranks.include?(higher) && existing_ranks.include?(lower)
  # do something
else
  # do another thing
end

Is there a more effective/efficient/ruby way to solve this problem?

Upvotes: 2

Views: 63

Answers (4)

steenslag
steenslag

Reputation: 80065

When a key is not found in a hash, then the result is nil.Just delete the nil to get the valid neighbor(s)

hash = {
  bronze: 0,
  silver: 1,
  gold: 2,
  platinum: 3,
  diamond: 4
}

given_rank = 'gold'
existing_ranks =  ['silver', 'platinum']

ranks = hash.invert
r = hash[given_rank.to_sym]
# compact method deletes nil values:
p existing_ranks.map(&:to_sym) == [ranks[r-1], ranks[r+1]].compact # => true

Upvotes: 0

Cary Swoveland
Cary Swoveland

Reputation: 110675

def correct_ordering?(hash, existing_ranks, given_rank)
  hash.values_at(*existing_ranks).sort == [hash[given_rank]-1, hash[given_rank]+1]
end

existing_ranks = [:silver, :platinum]

correct_ordering?(hash, existing_ranks, :gold)    #=> true
correct_ordering?(hash, existing_ranks, :diamond) #=> false

Upvotes: 0

tokland
tokland

Reputation: 67850

Using the trivial mathematical relationship between consecutive indexes, you can write:

n1, n2 = hash.values_at(*existing_ranks)
are_neighbors = (n1 - n2).abs == 2 && hash[given_rank] == (n1 + n2) / 2

Upvotes: 2

Caillou
Caillou

Reputation: 1500

A bit of advice, : work with symbols instead of strings for your ranks.

hash = {
  bronze: 0,
  silver: 1,
  gold: 2,
  platinum: 3,
  diamond: 4
}
given_rank = :gold
existing_ranks =  [:silver, :platinum]

is_neighbor = existing_ranks.map{ |rank| (hash[rank] - hash[given_rank]).abs }.uniq == [1]

Now you shoulod have is_neighbor == true if both of your existing_ranks is a neighbor of your given rank

Upvotes: 0

Related Questions