it-swarm.com.de

Wie entferne ich einen Schlüssel aus Hash und bekomme den restlichen Hash in Ruby / Rails?

So fügen Sie Hash I do ein neues Paar hinzu:

{:a => 1, :b => 2}.merge!({:c => 3})   #=> {:a => 1, :b => 2, :c => 3}

Gibt es eine ähnliche Möglichkeit, einen Schlüssel aus Hash zu löschen?

Das funktioniert:

{:a => 1, :b => 2}.reject! { |k| k == :a }   #=> {:b => 2}

aber ich würde folgendes erwarten:

{:a => 1, :b => 2}.delete!(:a)   #=> {:b => 2}

Es ist wichtig, dass der Rückgabewert der verbleibende Hash ist, damit ich folgende Dinge tun kann:

foo(my_hash.reject! { |k| k == my_key })

in einer Zeile.

514
Misha Moroshko

Rails hat eine except/except! -Methode , die den Hash mit den entfernten Schlüsseln zurückgibt. Wenn Sie Rails bereits verwenden, macht es keinen Sinn, eine eigene Version davon zu erstellen.

class Hash
  # Returns a hash that includes everything but the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false, c: nil}
  #
  # This is useful for limiting a set of parameters to everything but a few known toggles:
  #   @person.update(params[:person].except(:admin))
  def except(*keys)
    dup.except!(*keys)
  end

  # Replaces the hash without the given keys.
  #   hash = { a: true, b: false, c: nil}
  #   hash.except!(:c) # => { a: true, b: false}
  #   hash # => { a: true, b: false }
  def except!(*keys)
    keys.each { |key| delete(key) }
    self
  end
end
692
Peter Brown

Oneliner Ruby, es funktioniert nur mit Ruby> 1.9.x:

1.9.3p0 :002 > h = {:a => 1, :b => 2}
 => {:a=>1, :b=>2} 
1.9.3p0 :003 > h.tap { |hs| hs.delete(:a) }
 => {:b=>2} 

Tap Methode gibt immer das Objekt zurück, auf das zugegriffen wird ...

Andernfalls können Sie, wenn Sie active_support/core_ext/hash (der in jeder Rails -Anwendung automatisch erforderlich ist) angefordert haben, je nach Ihren Anforderungen eine der folgenden Methoden anwenden:

➜  ~  irb
1.9.3p125 :001 > require 'active_support/core_ext/hash' => true 
1.9.3p125 :002 > h = {:a => 1, :b => 2, :c => 3}
 => {:a=>1, :b=>2, :c=>3} 
1.9.3p125 :003 > h.except(:a)
 => {:b=>2, :c=>3} 
1.9.3p125 :004 > h.slice(:a)
 => {:a=>1} 

ausgenommen verwendet einen Blacklist-Ansatz, sodass alle als Argumente aufgelisteten Schlüssel entfernt werden, während Slice einen Whitelist-Ansatz verwendet, sodass alle Schlüssel entfernt werden, die nicht als Argumente aufgeführt sind. Es gibt auch die BANG-Version dieser Methoden (except! und slice!), die den angegebenen Hash modifizieren, deren Rückgabewert jedoch unterschiedlich ist. Beide geben einen Hash zurück. Es stellt die entfernten Schlüssel für slice! und die Schlüssel dar, die für except! aufbewahrt werden:

1.9.3p125 :011 > {:a => 1, :b => 2, :c => 3}.except!(:a)
 => {:b=>2, :c=>3} 
1.9.3p125 :012 > {:a => 1, :b => 2, :c => 3}.slice!(:a)
 => {:b=>2, :c=>3} 
192
Fabio

Warum nicht einfach:

hash.delete(key)
165
dbryson

Es gibt viele Möglichkeiten, einen Schlüssel aus einem Hash zu entfernen und den verbleibenden Hash in Ruby abzurufen.

  1. .slice => Ausgewählte Schlüssel werden zurückgegeben und nicht aus dem ursprünglichen Hash gelöscht. Verwenden Sie slice!, wenn Sie die Schlüssel dauerhaft entfernen möchten, andernfalls verwenden Sie einfach slice.

    2.2.2 :074 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :075 > hash.slice("one","two")
     => {"one"=>1, "two"=>2} 
    2.2.2 :076 > hash
     => {"one"=>1, "two"=>2, "three"=>3} 
    
  2. .delete => Löscht die ausgewählten Schlüssel aus dem ursprünglichen Hash (es kann nur einen Schlüssel und nicht mehr als einen akzeptieren).

    2.2.2 :094 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :095 > hash.delete("one")
     => 1 
    2.2.2 :096 > hash
     => {"two"=>2, "three"=>3} 
    
  3. .except => Die verbleibenden Schlüssel werden zurückgegeben, es wird jedoch nichts aus dem ursprünglichen Hash gelöscht. Verwenden Sie except!, wenn Sie die Schlüssel dauerhaft entfernen möchten, andernfalls verwenden Sie einfach except.

    2.2.2 :097 > hash = {"one"=>1, "two"=>2, "three"=>3}
     => {"one"=>1, "two"=>2, "three"=>3} 
    2.2.2 :098 > hash.except("one","two")
     => {"three"=>3} 
    2.2.2 :099 > hash
     => {"one"=>1, "two"=>2, "three"=>3}         
    
  4. .delete_if => Falls Sie einen Schlüssel basierend auf einem Wert entfernen müssen. Es werden offensichtlich die passenden Schlüssel aus dem ursprünglichen Hash entfernt.

    2.2.2 :115 > hash = {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1}
     => {"one"=>1, "two"=>2, "three"=>3, "one_again"=>1} 
    2.2.2 :116 > value = 1
     => 1 
    2.2.2 :117 > hash.delete_if { |k,v| v == value }
     => {"two"=>2, "three"=>3} 
    2.2.2 :118 > hash
     => {"two"=>2, "three"=>3} 
    
  5. .compact => Hiermit werden alle nil Werte aus dem Hash entfernt. Verwenden Sie compact!, wenn Sie die nil Werte dauerhaft entfernen möchten, andernfalls verwenden Sie einfach compact.

    2.2.2 :119 > hash = {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil}
     => {"one"=>1, "two"=>2, "three"=>3, "nothing"=>nil, "no_value"=>nil} 
    2.2.2 :120 > hash.compact
     => {"one"=>1, "two"=>2, "three"=>3}
    

Ergebnisse basierend auf Ruby 2.2.2.

67
techdreams

Wenn Sie pure Ruby (keine Rails) verwenden möchten, möchten Sie keine Erweiterungsmethoden erstellen (möglicherweise benötigen Sie diese nur an ein oder zwei Stellen und möchten den Namespace nicht mit unzähligen Methoden verschmutzen). und Sie möchten kein Hash an Ort und Stelle bearbeiten (dh Sie sind ein Fan von funktionaler Programmierung wie ich), können Sie Folgendes auswählen:

>> x = {:a => 1, :b => 2, :c => 3}
=> {:a=>1, :b=>2, :c=>3}
>> x.select{|x| x != :a}
=> {:b=>2, :c=>3}
>> x.select{|x| ![:a, :b].include?(x)}
=> {:c=>3}
>> x
=> {:a=>1, :b=>2, :c=>3}
37
Yura Taras
#in lib/core_extensions.rb
class Hash
  #pass single or array of keys, which will be removed, returning the remaining hash
  def remove!(*keys)
    keys.each{|key| self.delete(key) }
    self
  end

  #non-destructive version
  def remove(*keys)
    self.dup.remove!(*keys)
  end
end

#in config/initializers/app_environment.rb (or anywhere in config/initializers)
require 'core_extensions'

Ich habe dies so eingerichtet, dass .remove eine Kopie des Hashes mit entfernten Schlüsseln zurückgibt, während remove! ändert den Hash selbst. Dies entspricht den Ruby Konventionen. zB von der Konsole

>> hash = {:a => 1, :b => 2}
=> {:b=>2, :a=>1}
>> hash.remove(:a)
=> {:b=>2}
>> hash
=> {:b=>2, :a=>1}
>> hash.remove!(:a)
=> {:b=>2}
>> hash
=> {:b=>2}
>> hash.remove!(:a, :b)
=> {}
31
Max Williams

Sie können except! aus dem Edelstein facets verwenden:

>> require 'facets' # or require 'facets/hash/except'
=> true
>> {:a => 1, :b => 2}.except(:a)
=> {:b=>2}

Der ursprüngliche Hash ändert sich nicht.

BEARBEITEN: Wie Russel sagt, haben Facetten einige versteckte Probleme und sind nicht vollständig API-kompatibel mit ActiveSupport. Andererseits ist ActiveSupport nicht so vollständig wie Facetten. Am Ende würde ich AS verwenden und die Edge-Fälle in Ihrem Code belassen.

27
rewritten

Anstatt Affen zu patchen oder unnötigerweise große Bibliotheken einzuschließen, können Sie Verfeinerungen, wenn Sie Ruby 2 verwenden :

module HashExtensions
  refine Hash do
    def except!(*candidates)
      candidates.each { |candidate| delete(candidate) }
      self
    end

    def except(*candidates)
      dup.remove!(candidates)
    end
  end
end

Sie können diese Funktion verwenden, ohne andere Teile Ihres Programms zu beeinträchtigen oder große externe Bibliotheken einbeziehen zu müssen.

class FabulousCode
  using HashExtensions

  def incredible_stuff
    delightful_hash.except(:not_fabulous_key)
  end
end
19
Mohamad

in reinem Rubin:

{:a => 1, :b => 2}.tap{|x| x.delete(:a)}   # => {:b=>2}
17
gamov

Siehe Ruby on Rails: Löschen mehrerer Hash-Schlüssel

hash.delete_if{ |k,| keys_to_delete.include? k }
11
Nakilon

Es war großartig, wenn delete das Löschpaar des Hash zurückgibt. Ich mache das:

hash = {a: 1, b: 2, c: 3}
{b: hash.delete(:b)} # => {:b=>2}
hash  # => {:a=>1, :c=>3} 
3
frenesim

Dies ist eine einzeilige Methode, die jedoch nicht gut lesbar ist. Es wird empfohlen, stattdessen zwei Zeilen zu verwenden.

use_remaining_hash_for_something(Proc.new { hash.delete(:key); hash }.call)
1
the_minted

Mehrere Möglichkeiten zum Löschen von Key in Hash. Sie können jede Methode von unten verwenden

hash = {a: 1, b: 2, c: 3}
hash.except!(:a) # Will remove *a* and return HASH
hash # Output :- {b: 2, c: 3}

hash = {a: 1, b: 2, c: 3}
hash.delete(:a) # will remove *a* and return 1 if *a* not present than return nil

So viele Möglichkeiten gibt es, können Sie Ruby doc von Hash hier .

Danke

1
Ketan Mangukiya