Cách thay thế khóa băm bằng khóa khác


191

Tôi có một điều kiện, tôi nhận được một hàm băm

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

và tôi muốn hàm băm này là

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

Tái bút : Tôi không biết các khóa trong hàm băm là gì, chúng là ngẫu nhiên đi kèm với tiền tố "_" cho mọi khóa và tôi không muốn có dấu gạch dưới


Điều này có thể giúp bạn: stackoverflow.com/questions/4044451/ Cách
bị ăn mòn

+1 cho câu hỏi hữu ích
ashisrai_

@ a5his: Tôi rất vui vì đã được giúp đỡ :)
Manish Das

Câu trả lời:


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

8
Cứu tôi một đôi LỘC, yêu lắm!
nicohvi

10
Tôi thường không thích mã ruby ​​"thông minh" vì phải mất một thời gian để nói nó thực sự đang làm gì. Giải pháp của bạn là mặt khác đơn giản và mô tả.
Lucas

3
Đây thực sự nên là câu trả lời được chấp nhận! Dễ dàng, sạch sẽ và đi thẳng vào vấn đề!
GigaBass

1
Câu trả lời này là thanh lịch nhưng nó không thực sự trả lời câu hỏi. Bài đăng nói rằng các khóa cần thay thế là không xác định ... Chúng tôi chỉ biết rằng chúng bắt đầu bằng dấu gạch dưới, chúng tôi không biết khóa thực sự là gì.
Dsel

2
do đó, điều này tạo ra một cặp khóa / giá trị mới trong đó bạn chỉ định khóa mới và nhận giá trị từ những gì hash.delete :old_keytrả về và xóa sử dụng khóa cũ. WOW, tôi muốn nó được xăm ở đâu đó :-D Cảm ơn
Bart C

136

Rails Hash có phương thức chuẩn cho nó:

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

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

CẬP NHẬT: phương pháp ruby ​​2.5


4
Đó là phương pháp Rails, không chuẩn. Câu trả lời tốt mặc dù.
dùng2422869

1
Ngoài ra, phương pháp này không thể hoạt động với các khóa băm đệ quy.
Sergio Belevskij

5
deep_transform_keys có thể được sử dụng cho nó :) apidock.com/rails/v4.2.1/Hash/deep_transform_keys
gayavat

1
Cuối cùng! Đây chính xác là những gì tôi đã tìm kiếm!
TiSer

4
Đây là một phần tiêu chuẩn của ngôn ngữ kể từ Ruby 2.5: docs.ruby-lang.org/en/trunk/Hash.html#method-i-transform_keys
David Grayson

39

Nếu tất cả các khóa là các chuỗi và tất cả chúng đều có tiền tố gạch dưới, thì bạn có thể vá lỗi băm tại chỗ bằng cách này:

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

Các k[1, k.length - 1]bit lấy tất cảk ngoại trừ ký tự đầu tiên. Nếu bạn muốn có một bản sao, thì:

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

Hoặc là

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

Bạn cũng có thể sử dụng subnếu bạn không thíchk[] ký hiệu trích xuất một chuỗi con:

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 }

Và, nếu chỉ một số phím có tiền tố gạch dưới:

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

Sửa đổi tương tự có thể được thực hiện cho tất cả các biến thể khác ở trên nhưng hai biến thể sau:

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

sẽ ổn với các khóa không có tiền tố gạch dưới mà không cần sửa đổi thêm.


Câu trả lời của bạn đã có hiệu quả nhưng sau khi tôi tìm thấy vài hàm băm như thế này
Manish Das

3
{"_Iid" "=>" 4de7140472f8be03da000017 "," update_at "=>" 2011-06-02T10: 24: 35 + 05: 45 "}
Manish Das

2
{"id" => "4de7140772f8be03da000018", "type" => "WorkStation", "reat_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

@M Biến: Tôi đã nói "Nếu tất cả các khóa là chuỗi và tất cả chúng đều có tiền tố gạch dưới". Tôi đã bao gồm một cách tiếp cận ví dụ cho "các khóa không có tiền tố gạch dưới" trong một bản cập nhật.
mu quá ngắn ngày

2
@M Biến: "k" là "chìa khóa", "v" là "giá trị", "x" là "Tôi không biết gọi nó là gì nhưng tôi được đào tạo thành một nhà toán học nên tôi gọi nó là x".
mu quá ngắn ngày

14

bạn có thể làm

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

Điều này sẽ làm việc cho trường hợp của bạn!


11

Nếu chúng ta muốn đổi tên một khóa cụ thể trong hàm băm thì chúng ta có thể thực hiện như sau:
Giả sử hàm băm của tôi là my_hash = {'test' => 'ruby hash demo'}
Bây giờ tôi muốn thay thế 'test' bằng 'message', sau đó:
my_hash['message'] = my_hash.delete('test')


Làm thế nào là câu trả lời của bạn là giải pháp cho vấn đề của tôi? Nếu bạn nghĩ rằng điều này là hữu ích, thì bạn có thể đã thêm vào bình luận dưới câu hỏi. Câu hỏi của tôi không phải là thay thế một khóa bằng một khóa khác, giải pháp bạn đưa ra là thuộc tính Hash rất cơ bản. trong trường hợp của tôi thì không phải : hash[:new_key] = has[:old_key], thay vào đó là : hash[:dynamic_key] = hash[:_dynamic_key], đó là câu hỏi rõ ràng về regex và thay thế hàm băm đơn giản.
Manish Das

2
Tôi đã đến đây thông qua một tìm kiếm google và muốn câu trả lời của @ Swapnil. Cảm ơn
toobulkeh

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

4
Tôi thích rằng bạn đã cố gắng sử dụng regex để lọc các dấu gạch dưới một cách chính xác, nhưng bạn nên lưu ý rằng trong ruby, không giống như javascript và các loại khác, / ^ / có nghĩa là 'bắt đầu chuỗi OR LINE' và / $ / có nghĩa là 'kết thúc chuỗi HOẶC LINE '. Không chắc là các khóa có dòng mới trong trường hợp này, nhưng bạn nên lưu ý rằng việc sử dụng hai toán tử đó trong ruby ​​không chỉ dễ bị lỗi mà còn rất nguy hiểm khi sử dụng sai trong xác nhận chống tiêm. Xem ở đây để giải thích. Hy vọng bạn không phiền truyền bá nhận thức.
Jorn van de Beek

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

1

Tôi đã đi quá mức cần thiết và đưa ra những điều sau đây. Động lực của tôi đằng sau điều này là gắn thêm các khóa băm để tránh xung đột phạm vi khi hợp nhất các hàm băm / làm phẳng.

Ví dụ

Mở rộng lớp Hash

Thêm phương thức rekey vào các thể hiện 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

Ví dụ chuẩn bị

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

Ví dụ Trim

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

Làm phẳng và gắn một "Phạm vi"

Nếu bạn chuyển một hàm băm trở lại để rekey, nó sẽ hợp nhất hàm băm cho phép bạn làm phẳng các bộ sưu tập. Điều này cho phép chúng tôi thêm phạm vi vào các khóa của mình khi làm phẳng hàm băm để tránh ghi đè khóa khi hợp nhất.

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

Câu trả lời trước là đủ tốt, nhưng họ có thể cập nhật dữ liệu gốc. Trong trường hợp nếu bạn không muốn dữ liệu gốc bị ảnh hưởng, bạn có thể thử mã của tôi.

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

Đầu tiên, nó sẽ bỏ qua khóa '_id', sau đó hợp nhất với khóa được cập nhật.

Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.