Jak zastąpić klucz skrótu innym kluczem

192

Mam stan, w którym dostaję skrót

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

i chcę ten hash jako

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

PS : Nie wiem, jakie są klucze w skrócie, są losowe, z każdym prefiksem „_” i nie chcę żadnych znaków podkreślenia

Manish Das
źródło
To może ci pomóc: stackoverflow.com/questions/4044451/…
skorodowane
+1 za przydatne pytanie
ashisrai_
@ a5his: Cieszę się, że to pomogło :)
Manish Das

Odpowiedzi:

711
hash[:new_key] = hash.delete :old_key
gayavat
źródło
8
Uratowałem mi kilka LOC, uwielbiam to!
nicohvi
10
Często nie lubię „inteligentnego” kodu ruby, ponieważ zajmuje trochę czasu, aby stwierdzić, co naprawdę robi. Twoje rozwiązanie jest z drugiej strony proste i opisowe.
Lucas
3
To rzeczywiście powinna być zaakceptowana odpowiedź! Łatwo, czysto i od razu do rzeczy!
GigaBass
1
Ta odpowiedź jest elegancka, ale tak naprawdę nie odpowiada na pytanie. W poście stwierdza się, że klucze, które wymagają wymiany, są nieznane ... Wiemy tylko, że zaczynają się od podkreślenia, nie wiemy, czym tak naprawdę są klucze.
Dsel,
2
tworzy to nową parę klucz / wartość, w której określasz nowy klucz i uzyskujesz wartość z tego, co hash.delete :old_keyzwraca, a usuwanie używa starego klucza. WOW, chcę to gdzieś wytatuować :-D Dzięki
Bart C
136

szyny Hash ma do tego standardową metodę:

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

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

UPD: metoda ruby ​​2.5

gayavat
źródło
4
Jest to metoda Railsowa, niestandardowa. Dobra odpowiedź.
user2422869,
1
Ponadto ta metoda nie może rekurencyjnie działać z kluczami skrótu.
Sergio Belevskij
5
Można do tego użyć deep_transform_keys
gayavat
1
W końcu! Właśnie tego szukałem!
TiSer
4
Jest to standardowa część języka Ruby 2.5: docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
David Grayson
39

Jeśli wszystkie klucze są ciągami znaków i wszystkie mają przedrostek podkreślenia, możesz załatać skrót w tym miejscu:

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

k[1, k.length - 1]Nieco łapie wszystkie kz wyjątkiem pierwszego znaku. Jeśli chcesz kopię, to:

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

Lub

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

Możesz także użyć, subjeśli nie podoba ci się k[]notacja do wyodrębniania podłańcucha:

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 }

A jeśli tylko niektóre klucze mają prefiks podkreślenia:

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

Podobne modyfikacje można wprowadzić dla wszystkich pozostałych wariantów powyżej, ale te dwa:

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

powinno być w porządku z kluczami, które nie mają prefiksów podkreślenia bez dodatkowych modyfikacji.

mu jest za krótki
źródło
twoja odpowiedź zadziałała, ale po totemie znalazłem kilka takich skrótów
Manish Das
3
{"_id" => „4de7140772f8be03da000018”, „_type” => „WorkStation”, „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: Powiedziałem „Jeśli wszystkie klucze są ciągami znaków i wszystkie mają przedrostek podkreślenia”. W aktualizacji umieściłem przykładowe podejście do „kluczy bez prefiksów podkreślenia”.
mu jest za krótki
2
@Manish: „k” oznacza „klucz”, „v” oznacza „wartość”, „x” oznacza „nie wiem, jak to nazwać, ale zostałem przeszkolony jako matematyk, więc nazywam to x”.
mu jest za krótki
14

możesz to zrobić

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

To powinno działać w twoim przypadku!

Sadiksha Gautam
źródło
11

Jeśli chcemy zmienić nazwę określonego klucza w skrócie, możemy to zrobić w następujący sposób:
Załóżmy, że mój skrót to my_hash = {'test' => 'ruby hash demo'}
Teraz chcę zastąpić słowo „test” słowem „wiadomość”, a następnie:
my_hash['message'] = my_hash.delete('test')

Swapnil Chincholkar
źródło
Jak zatem twoja odpowiedź jest rozwiązaniem mojego problemu? Jeśli uważasz, że to było pomocne, mógłbyś dodać komentarz w pytaniu. Moim pytaniem nie było zastąpienie klucza innym kluczem, rozwiązanie, które podałeś, jest bardzo podstawową właściwością skrótu. w moim przypadku nie jest to: hash[:new_key] = has[:old_key]zamiast tego: hash[:dynamic_key] = hash[:_dynamic_key]było jasne pytanie o wyrażenie regularne i nie prosty zamiennik skrótu.
Manish Das,
2
Doszedłem do tego za pomocą wyszukiwarki Google i chciałem uzyskać odpowiedź @ Swapnil. Dzięki
toobulkeh
10
h.inject({}) { |m, (k,v)| m[k.sub(/^_/,'')] = v; m }
DigitalRoss
źródło
4
Podoba mi się, że próbowałeś użyć wyrażenia regularnego, aby odpowiednio odfiltrować podkreślenia, ale powinieneś pamiętać, że w Rubim, w przeciwieństwie do javascript i innych, / ^ / oznacza „początek łańcucha OR LINE”, a / $ / oznacza „koniec ciąg LUB LINIA ”. W tym przypadku jest mało prawdopodobne, aby klucze zawierały nowe wiersze, ale należy pamiętać, że używanie tych dwóch operatorów w Rubim jest nie tylko podatne na błędy, ale także bardzo niebezpieczne, gdy jest źle stosowane w sprawdzaniu poprawności przeciwko wstrzyknięciom. Zobacz tutaj wyjaśnienie. Mam nadzieję, że nie masz nic przeciwko szerzeniu świadomości.
Jorn van de Beek,
2
hash.each {|k,v| hash.delete(k) && hash[k[1..-1]]=v if k[0,1] == '_'}
maerika
źródło
1

Poszedłem za przesadnie i wymyśliłem następujące rzeczy. Moją motywacją było dołączenie do klawiszy skrótu, aby uniknąć konfliktów zakresu podczas scalania / spłaszczania skrótów.

Przykłady

Rozszerz klasę mieszania

Dodaje metodę rekey do instancji Hash.

# 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

Przygotuj przykład

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..."}

Przykład przycinania

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

Spłaszczanie i dołączanie „zakresu”

Jeśli przekażesz skrót z powrotem w celu ponownego wygenerowania, spowoduje to scalenie skrótu, co pozwala spłaszczyć kolekcje. To pozwala nam dodać zakres do naszych kluczy podczas spłaszczania skrótu, aby uniknąć zastąpienia klucza podczas scalania.

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"}
#   ]
# }
CTS_AE
źródło
0

Poprzednie odpowiedzi są wystarczająco dobre, ale mogą aktualizować oryginalne dane. Jeśli nie chcesz, aby oryginalne dane zostały naruszone, możesz wypróbować mój kod.

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

Najpierw zignoruje klucz „_id”, a następnie połączy się ze zaktualizowanym.

purushothaman poovai
źródło