Frage

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}
War es hilfreich?

Lösung

Just do this:

deck_of_cards[:clubs].delete(:two)

Andere Tipps

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')
Lizenziert unter: CC-BY-SA mit Zuschreibung
Nicht verbunden mit StackOverflow
scroll top