Reputation: 10997
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
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
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
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
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