Bir karma anahtarı başka bir anahtarla değiştirme


192

Bir hash bulduğum bir durumum var

  hash = {"_id"=>"4de7140772f8be03da000018", .....}

ve bu karmayı istiyorum

  hash = {"id"=>"4de7140772f8be03da000018", ......}

PS : Karma anahtarlar nedir bilmiyorum, onlar rastgele her anahtar için "_" öneki ile geliyor ve alt çizgi istemiyorum



Yararlı soru için +1
ashisrai_

@ a5his: Yardım ettiğine sevindim :)
Manish Das

Yanıtlar:


711
hash[:new_key] = hash.delete :old_key

8
Bana bir kaç LOC kurtardım, seviyorum!
nicohvi

10
Sık sık "akıllı" yakut kodunu sevmiyorum çünkü gerçekten ne yaptığını söylemek biraz zaman alıyor. Çözümünüz diğer taraftan basit ve açıklayıcıdır.
Lucas

3
Bu gerçekten kabul edilen cevap olmalı! Kolay, temiz ve doğrudan noktaya!
GigaBass

1
Bu cevap zarif ama soruya aslında cevap vermiyor. Mesaj, değiştirilmesi gereken anahtarların bilinmediğini söylüyor ... Sadece alt çizgiyle başladıklarını biliyoruz, anahtarların gerçekte ne olduğunu bilmiyoruz.
Dsel

2
böylece bu, yeni anahtarı belirlediğiniz ve hash.delete :old_keydöndürülen değeri aldığınız ve silme işleminin eski anahtarı kullandığı yeni bir anahtar / değer çifti oluşturur . VAY, bir yere dövmeli istiyorum :-D Teşekkürler
Bart C

136

raylar Hash bunun için standart bir yönteme sahiptir:

hash.transform_keys{ |key| key.to_s.upcase }

http://api.rubyonrails.org/classes/Hash.html#method-i-transform_keys

UPD: yakut 2.5 yöntemi


4
Rails yöntemi, standart değil. Yine de iyi bir cevap.
user2422869

1
Ayrıca, bu yöntem karma anahtarlarla özyinelemeli olarak çalışamaz.
Sergio Belevskij

5
deep_transform_keys bunun için kullanılabilir :) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat

1
Sonunda! Aradığım şey tam olarak bu!
TiSer

4
Bu Ruby 2.5'ten itibaren dilin standart bir parçasıdır: docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
David Grayson

39

Tüm tuşlar dize ise ve hepsinde alt çizgi öneki varsa, hash'ı bununla yamalayabilirsiniz:

h.keys.each { |k| h[k[1, k.length - 1]] = h[k]; h.delete(k) }

k[1, k.length - 1]Biraz tüm kapmak kilk karakteri hariç. Bir kopyasını istiyorsanız, o zaman:

new_h = Hash[h.map { |k, v| [k[1, k.length - 1], v] }]

Veya

new_h = h.inject({ }) { |x, (k,v)| x[k[1, k.length - 1]] = v; x }

Bir alt dizeyi çıkarmak subiçin k[]gösterimi beğenmediyseniz de kullanabilirsiniz :

h.keys.each { |k| h[k.sub(/\A_/, '')] = h[k]; h.delete(k) }
Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

Ve, yalnızca bazı tuşlarda alt çizgi öneki varsa:

h.keys.each do |k|
  if(k[0,1] == '_')
    h[k[1, k.length - 1]] = h[k]
    h.delete(k)
  end
end

Benzer değişiklikler yukarıdaki diğer tüm varyantlarda yapılabilir, ancak bu ikisi:

Hash[h.map { |k, v| [k.sub(/\A_/, ''), v] }]
h.inject({ }) { |x, (k,v)| x[k.sub(/\A_/, '')] = v; x }

fazladan değişiklik yapılmadan alt çizgi önekleri olmayan tuşlar ile uyumlu olmalıdır.


senin cevap çalıştı ama koğuştan sonra böyle birkaç hash buldum
Manish Das

3
{"_id" => "4de7140772f8be03da000018", "_type" => "İş İstasyonu", "created_at" => "2011-06-02T10: 24: 35 + 05: 45", "input_header_ids" => [], "line_id "=>" 4de7140472f8be03da000017 "," updated_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Manish Das

2
{"id" => "4de7140772f8be03da000018", "type" => "WorkStation", "reated_at" => "2011-06-02T10: 24: 35 + 05: 45", "nput_header_ids" => [], "ine_id "=>" 4de7140472f8be03da000017 "," pdated_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Manish Das

@Manish: "Tüm anahtarlar dizgiyse ve hepsinin alt çizgi öneki varsa" dedim. Bir güncellemeye "alt çizgi önekleri olmayan anahtarlar" için örnek bir yaklaşım ekledim.
mu çok kısa

2
@Manish: "k", "anahtar" içindir, "v", "değer" içindir, "x", "ne diyeceğimi bilmiyorum ama matematikçi olarak eğitildim, bu yüzden x diyorum".
mu çok kısa

14

yapabilirsin

hash.inject({}){|option, (k,v) | option["id"] = v if k == "_id"; option}

Bu sizin davanız için işe yarar!


11

Karma içindeki belirli bir anahtarı yeniden adlandırmak istiyorsak, bunu şu şekilde yapabiliriz: Şimdi
benim karma my_hash = {'test' => 'ruby hash demo'}
olduğumu varsayalım.
my_hash['message'] = my_hash.delete('test')


O zaman cevabın benim sorunum için nasıl bir çözüm? Bunun yararlı olduğunu düşünüyorsanız, sorunun altındaki yorumu ekleyebilirdiniz. Benim sorum bir anahtarı başka bir anahtarla değiştirmek değildi, verdiğiniz çözüm çok temel Hash özelliğidir. benim durumumda değil:, hash[:new_key] = has[:old_key]bunun yerine:, hash[:dynamic_key] = hash[:_dynamic_key]regex ve basit karma yerine açık bir soru oldu.
Manish Das

2
Buna bir google aramasıyla geldim ve @ Swapnil'in cevabını istedim. Thanks
toobulkeh

10
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }

4
Alt çizgileri düzgün bir şekilde filtrelemek için bir regex kullanmaya çalıştığınızı sevdim, ancak yakutta, javascript ve diğerlerinin aksine, / ^ / 'dizginin VEYA LINE'ın başlangıcı' ve / $ / 'ifadesinin sonu anlamına geldiğini bilmelisiniz. dize VEYA HATTI '. Bu durumda tuşların içinde yeni satırlar olması olası değildir, ancak bu iki operatörü ruby'de kullanmanın sadece hataya eğilimli değil, aynı zamanda enjeksiyonlara karşı yapılan onaylamalarda yanlış kullanıldığında da çok tehlikeli olduğunu bilmelisiniz. Bir açıklama için buraya bakın . Umarım farkındalığı yaymak sakıncası olmaz.
Jorn van de Beek

2
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}

1

Ben aşırıya kaçtım ve aşağıdaki ile geldim. Bunun arkasındaki motivasyon, karmaları birleştirirken / düzleştirirken kapsam çakışmalarını önlemek için hash anahtarlarına eklemekti.

Örnekler

Karma Sınıfını Genişlet

Hash örneklerine rekey yöntemi ekler.

# Adds additional methods to Hash
class ::Hash
  # Changes the keys on a hash
  # Takes a block that passes the current key
  # Whatever the block returns becomes the new key
  # If a hash is returned for the key it will merge the current hash 
  # with the returned hash from the block. This allows for nested rekeying.
  def rekey
    self.each_with_object({}) do |(key, value), previous|
      new_key = yield(key, value)
      if new_key.is_a?(Hash)
        previous.merge!(new_key)
      else
        previous[new_key] = value
      end
    end
  end
end

Başa Örnek

my_feelings_about_icecreams = {
  vanilla: 'Delicious',
  chocolate: 'Too Chocolatey',
  strawberry: 'It Is Alright...'
}

my_feelings_about_icecreams.rekey { |key| "#{key}_icecream".to_sym }
# => {:vanilla_icecream=>"Delicious", :chocolate_icecream=>"Too Chocolatey", :strawberry_icecream=>"It Is Alright..."}

Trim Örneği

{ _id: 1, ___something_: 'what?!' }.rekey do |key|
  trimmed = key.to_s.tr('_', '')
  trimmed.to_sym
end
# => {:id=>1, :something=>"what?!"}

"Kapsam" Düzleştirme ve Ekleme

Bir karma değerini yeniden anahtarlamak için geri gönderirseniz, koleksiyonları düzleştirmenize izin veren karma birleştirilir. Bu, birleştirme sırasında bir anahtarın üzerine yazılmasını önlemek için bir karmayı düzleştirirken anahtarlarımıza kapsam eklememizi sağlar.

people = {
  bob: {
    name: 'Bob',
    toys: [
      { what: 'car', color: 'red' },
      { what: 'ball', color: 'blue' }
    ]
  },
  tom: {
    name: 'Tom',
    toys: [
      { what: 'house', color: 'blue; da ba dee da ba die' },
      { what: 'nerf gun', color: 'metallic' }
    ]
  }
}

people.rekey do |person, person_info|
  person_info.rekey do |key|
    "#{person}_#{key}".to_sym
  end
end

# =>
# {
#   :bob_name=>"Bob",
#   :bob_toys=>[
#     {:what=>"car", :color=>"red"},
#     {:what=>"ball", :color=>"blue"}
#   ],
#   :tom_name=>"Tom",
#   :tom_toys=>[
#     {:what=>"house", :color=>"blue; da ba dee da ba die"},
#     {:what=>"nerf gun", :color=>"metallic"}
#   ]
# }

0

Önceki yanıtlar yeterince iyi, ancak orijinal verileri güncelleyebilirler. Orijinal verilerin etkilenmesini istemiyorsanız, kodumu deneyebilirsiniz.

 newhash=hash.reject{|k| k=='_id'}.merge({id:hash['_id']})

Önce '_id' anahtarını yok sayar ve güncellenen anahtarla birleştirilir.

Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.