从嵌套哈希中删除特定元素

27

我正在尝试使用嵌套哈希表进行操作。我有一副以以下方式表示的纸牌:

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}
}
我的目标是能够从牌堆中删除一张特定的牌,并返回不含该牌的牌堆。请问有谁能帮忙指导如何遍历哈希表并删除像草花2这样的牌吗?
```html

我的目标是能够从牌堆中删除一张特定的牌,并返回不含该牌的牌堆。请问有谁能帮忙指导如何遍历哈希表并删除像草花2这样的牌吗?

```
deck_of_cards[:two][:clubs]

这段代码可以移除一副牌,但我无法弄清如何移除特定的一张牌。

deck_of_cards.delete_if {|k, v| k == :spades}
7个回答

47

只需要这样做:

deck_of_cards[:clubs].delete(:two)

10
有没有办法完全获取新的元素? 因为这段代码返回已删除的元素。 - sidney

7
您可以使用tap功能来移除元素并返回原始哈希值,示例代码如下:
deck_of_cards.tap{|d| 
  d[:hearts].tap{|h| 
    h.delete(:two)
  }
}

这将返回不带“:two”键的deck_if_cards哈希。您也可以在一行中完成它。
    deck_of_cards.tap{|d| d[:hearts].tap{|h| h.delete("two")}}

我认为你的"two"应该是:two吧? - Joshua Pinter
1
tap 在某些情况下确实很有帮助,但您不需要嵌套它:deck_of_cards.tap{|d| d[:hearts].delete(:two)} 就足够了。 - Hart Simha

4

使用.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} 
#   }

以一种优雅的方式返回完整的哈希值,而不仅仅是删除的值。


1

我在我的应用程序中编写了这个初始化器,以添加一个名为delete_nested_key的方法到哈希对象中。它可以删除哈希的嵌套键。您需要将key_path作为数组传递(只是要遍历的键的列表,以便找到要删除的键)。

它似乎能够正常工作,但我刚刚编写了它,所以可能存在问题。

class Hash
  module NestedKeyDeletion
    extend ActiveSupport::Concern

    included do
      def deleted_nested_key!(key_path)
        nested_hash = fetch_most_inner_hash(key_path)
        nested_hash.delete(key_path.last)

        self
      end

      private

      def fetch_most_inner_hash(key_path)
        nested_hash = self

        key_path.each_with_index do |key, index|
          return  nested_hash if index == key_path.size - 1
          nested_hash = nested_hash.fetch(key)
        end
      end
    end
  end
end

Hash.include(Hash::NestedKeyDeletion)

然后你可以像这样使用它:
[1] pry(main)> x = { x: { y: 2} }
=> {:x=>{:y=>2}}
[2] pry(main)> x.deleted_nested_key!([:x, :y])
=> {:x=>{}}
[3] pry(main)>

最好的问候, 丹尼尔。


0
你需要做的是这样的:
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

最好将您的牌组表示为一对数组,就像这样:

[ [:hearts, :two], [:hearts, :three], ... ]

然后你可以直接去:

def remove_card deck, suit, number
  deck.reject { |(s, n)| n == number and s == suit }
end

0

你有一个哈希内部的哈希,所以你可以这样做:

deck_of_cards.each {|k,v| v.delete(:two) if k == :clubs}

你可以使用each来迭代键和值,在块内部设置条件以删除内部哈希表中的特定值。

低估的解决方案! - Akash Agarwal
5
为什么要迭代哈希表,当你可以通过键直接访问子哈希表? - Bustikiller

0

我认为这个方法会适合你的需求

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

假设你想从牌堆 '红桃' 中删除 '六' 这张牌,你只需要执行以下操作:

deck_of_cards.nested_delete(card: 'six', deck: 'hearts')

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接