해시 키를 다른 키로 바꾸는 방법


192

해시를 얻는 조건이 있습니다.

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

이 해시를

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

추신 : 해시의 키가 무엇인지 모르겠습니다. 키마다 임의의 "_"접두사가 붙어 무작위로 밑줄을 원하지 않습니다.


이것은 당신을 도울 수 있습니다 : stackoverflow.com/questions/4044451/…
부식

유용한 질문에 +1
ashisrai_ 2016 년

@ a5his : 도움이되어서 기쁘다 :)
Manish Das

답변:


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

8
나에게 몇 LOC를 저장, 사랑해!
nicohvi 2016 년

10
나는 종종 "스마트 한"루비 코드를 좋아하지 않는다. 왜냐하면 그것이 실제로 무엇을하고 있는지 말하기 위해서는 약간의 시간이 걸리기 때문이다. 반면에 솔루션은 간단하고 설명이 간단합니다.
Lucas

3
이것은 실제로 받아 들여지는 대답이어야합니다! 쉽고 깨끗하고 바로 포인트!
GigaBass

1
이 답변은 우아하지만 실제로 질문에 대답하지는 않습니다. 게시물에 교체가 필요한 키를 알 수 없음이 명시되어 있습니다. 우리는 키가 밑줄로 시작한다는 것을 알고 있으며 키가 실제로 무엇인지 알 수 없습니다.
Dsel

2
따라서 새 키 / 값 쌍을 작성하여 새 키를 지정하고 hash.delete :old_key리턴 된 값에서 값을 가져 오면 삭제는 이전 키를 사용합니다. 와우, 나는 어딘가에 문신을하고 싶다 : -D Thanks
Bart C

136

레일 해시는 표준 방법을 가지고 있습니다 :

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

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

UPD : 루비 2.5 방법


4
Rails 방식은 표준이 아닙니다. 그래도 좋은 대답입니다.
user2422869

1
또한이 방법은 해시 키를 재귀 적으로 사용할 수 없습니다.
Sergio Belevskij

5
deep_transform_keys 사용할 수 있습니다 :) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat

1
마침내! 이것은 내가 찾은 것입니다!
TiSer

4
이것은 루비 2.5과 같은 언어의 표준 일부입니다 docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
데이비드 그레이

39

모든 키가 문자열이고 모두 밑줄 접두사가 있으면 다음과 같이 해시를 패치 할 수 있습니다.

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

k[1, k.length - 1]비트를 모두 잡고 k첫 번째 문자를 제외하고. 사본을 원하면 다음을 수행하십시오.

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

또는

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

부분 문자열 추출에 대한 표기법이 sub마음에 들지 않을 경우 에도 사용할 수 있습니다 k[].

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 }

그리고 일부 키에만 밑줄 접두사가있는 경우 :

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

위의 다른 모든 변형에 대해 유사한 수정을 수행 할 수 있지만 다음 두 가지가 있습니다.

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

밑줄이없는 키는 추가 수정없이 사용할 수 있습니다.


당신은 일을 대답 할하지만 병동 후 나는 다음과 같은 몇 가지 해시를 발견
마니 다스를

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 : "모든 키가 문자열이고 모두 밑줄 접두사가있는 경우"라고 말했습니다. 업데이트에 "밑줄이없는 키"에 대한 예제 접근 방식을 포함 시켰습니다.
mu는 너무 짧다

2
@Manish : "k"는 "key", "v"는 "value", "x"는 "무엇을 부를지 모르지만 수학자로 훈련되었으므로 x라고 부릅니다."
mu는 너무 짧다

14

넌 할 수있어

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

이것은 귀하의 경우에 효과가 있습니다!


11

해시에서 특정 키의 이름을 바꾸려면 다음과 같이 해시 할 수 있습니다.
해시가 있다고 가정 합니다. my_hash = {'test' => 'ruby hash demo'}
이제 'test'를 'message'로 바꾸고 싶습니다.
my_hash['message'] = my_hash.delete('test')


그러면 귀하의 답변은 어떻게 내 문제에 대한 해결책입니까? 도움이되었다고 생각되면 질문 아래에 의견을 추가했을 수도 있습니다. 내 질문은 키를 다른 키로 대체하지는 않았으므로 제공 한 솔루션은 매우 기본적인 해시 속성입니다. 내 경우에는 :이 아니라 : hash[:new_key] = has[:old_key]대신 : : hash[:dynamic_key] = hash[:_dynamic_key]정규식에 대한 명확한 질문이었고 간단한 해시 바꾸기가 아닙니다.
Manish Das

2
Google 검색을 통해이 문제를 해결하고 @Swapnil의 답변을 원했습니다. 감사합니다
toobulkeh

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

4
정규 표현식을 사용하여 밑줄을 올바르게 필터링하려고 시도했지만 Javascript 및 기타와 달리 루비에서는 / ^ /는 '문자열 OR 라인의 시작'을 의미하고 / $ /는 '끝을 의미합니다 문자열 또는 LINE '. 이 경우 키에 줄 바꿈이 없을 가능성은 낮지 만 루비에서이 두 연산자를 사용하면 오류가 발생하기 쉬울뿐 아니라 주입에 대한 유효성 검사에 잘못 사용될 때 매우 위험하다는 점에 유의해야합니다. 설명 은 여기 를 참조 하십시오 . 인식을 널리 알리지 않기를 바랍니다.
Jorn van de Beek

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

1

나는 과잉으로 가서 다음을 생각해 냈습니다. 이것의 배후의 동기는 해시를 병합 / 병합 할 때 범위 충돌을 피하기 위해 해시 키를 추가하는 것이 었습니다.

해시 클래스 확장

키 다시 작성 방법을 해시 인스턴스에 추가합니다.

# 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

접두사 예

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

트림 예

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

"범위"평탄화 및 추가

해시를 다시 키로 다시 전달하면 해시가 병합되어 컬렉션을 평평하게 할 수 있습니다. 이를 통해 해시를 병합 할 때 병합 할 때 키를 덮어 쓰지 않도록 키 범위를 추가 할 수 있습니다.

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

이전 답변으로는 충분하지만 원본 데이터를 업데이트 할 수 있습니다. 원본 데이터에 영향을 미치지 않으려면 내 코드를 사용해보십시오.

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

먼저 '_id'키를 무시한 다음 업데이트 된 키와 병합합니다.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.