Deleting a specific element from a nested hash
-
16-06-2021 - |
题
I am trying to work with a nested hash. I have a deck of cards represented as follows:
deck_of_cards = {
:hearts => {:two => 2, :three => 3, :four => 4, :five => 5, :six => 6, :seven => 7, :eight => 8, :nine => 9, :ten => 10, :jack => 10,
:queen => 10, :king => 10, :ace => 11},
:spades => {:two => 2, :three => 3, :four => 4, :five => 5, :six => 6, :seven => 7, :eight => 8, :nine => 9, :ten => 10, :jack => 10,
:queen => 10, :king => 10, :ace => 11},
:clubs => {:two => 2, :three => 3, :four => 4, :five => 5, :six => 6, :seven => 7, :eight => 8, :nine => 9, :ten => 10, :jack => 10,
:queen => 10, :king => 10, :ace => 11},
:diamonds => {:two => 2, :three => 3, :four => 4, :five => 5, :six => 6, :seven => 7, :eight => 8, :nine => 9, :ten => 10, :jack => 10,
:queen => 10, :king => 10, :ace => 11}
}
My goal is to be able to remove one specific card from the deck and return the deck of cards without that specific card. Would anyone be able to help me on how to iterate through the hash and remove a card like the two of clubs?
deck_of_cards[:two][:clubs]
This code works to remove a suit of cards, but I cant figure out how to remove a specific card
deck_of_cards.delete_if {|k, v| k == :spades}
解决方案
Just do this:
deck_of_cards[:clubs].delete(:two)
其他提示
You can remove an element and return the original hash also using tap function like this
deck_of_cards.tap{|d|
d[:hearts].tap{|h|
h.delete(:two)
}
}
this will return the deck_if_cards hash without :two key
you can do it in one line also
deck_of_cards.tap{|d| d[:hearts].tap{|h| h.delete("two")}}
Use .tap
deck_of_cards.tap{ |deck_of_cards| deck_of_cards[:hearts].delete(:two) }
#=> {
# :hearts=>{:three=>3, :four=>4, :five=>5, :six=>6, :seven=>7, :eight=>8, :nine=>9, :ten=>10, :jack=>10, :queen=>10, :king=>10, :ace=>11},
# :spades=>{:two=>2, :three=>3, :four=>4, :five=>5, :six=>6, :seven=>7, :eight=>8, :nine=>9, :ten=>10, :jack=>10, :queen=>10, :king=>10, :ace=>11},
# :clubs=>{:two=>2, :three=>3, :four=>4, :five=>5, :six=>6, :seven=>7, :eight=>8, :nine=>9, :ten=>10, :jack=>10, :queen=>10, :king=>10, :ace=>11},
# :diamonds=>{:two=>2, :three=>3, :four=>4, :five=>5, :six=>6, :seven=>7, :eight=>8, :nine=>9, :ten=>10, :jack=>10, :queen=>10, :king=>10, :ace=>11}
# }
Has the benefit of returning the full hash instead of just the deleted value in an elegant way.
You have a hash inside a hash, so you can do this:
deck_of_cards.each {|k,v| v.delete(:two) if k == :clubs}
You use each
to iterate through keys and values, and make a condition inside the block to delete the specific value on the inner hash.
You would have to is something like this:
def remove_card deck, suit, number
# do a deep clone
new_deck = {}
deck.each { |k, v| new_deck[k] = v.dup }
# remove the card
new_deck[suit] = new_deck[suit].reject { |k, v| k == number }
new_deck
end
It might be better to represent your deck as an array of pairs, like this:
[ [:hearts, :two], [:hearts, :three], ... ]
Then you can just go:
def remove_card deck, suit, number
deck.reject { |(s, n)| n == number and s == suit }
end
I think this method will do the job for you
def nested_delete(card:, deck:)
each do |hash_key, hash_value|
if hash_key.to_s.eql?(deck)
self[hash_key].delete(card.to_sym)
end
end
self
end
Say you want to delete card 'six' from deck 'hearts' All you need to do is
deck_of_cards.nested_delete(card: 'six', deck: 'hearts')