วิธีค้นหาคีย์แฮชที่มีค่าที่ตรงกัน


198

เนื่องจากฉันมีแฮชของไคลเอนต์ด้านล่างมีวิธี ruby ​​อย่างรวดเร็ว (โดยไม่ต้องเขียนสคริปต์หลายบรรทัด) เพื่อรับคีย์เนื่องจากฉันต้องการจับคู่ client_id หรือไม่ เช่นจะรับกุญแจได้client_id == "2180"อย่างไร

clients = {
  "yellow"=>{"client_id"=>"2178"}, 
  "orange"=>{"client_id"=>"2180"}, 
  "red"=>{"client_id"=>"2179"}, 
  "blue"=>{"client_id"=>"2181"}
}

คำตอบ:


176

คุณสามารถใช้Enumerable # select :

clients.select{|key, hash| hash["client_id"] == "2180" }
#=> [["orange", {"client_id"=>"2180"}]]

โปรดทราบว่าผลลัพธ์จะเป็นอาร์เรย์ของค่าการจับคู่ทั้งหมดโดยที่แต่ละค่าเป็นอาร์เรย์ของคีย์และค่า


22
@Coderama ความแตกต่างระหว่างfindและselectที่findจะส่งกลับนัดแรกและselect(ซึ่งเป็นนามแฝงโดยfindAll) ส่งคืนการแข่งขันทั้งหมด
Daniel Vandersluis

ฉันเห็นแล้วดังนั้นนี่จะเป็นตัวเลือกที่ปลอดภัยยิ่งขึ้นสำหรับกรณีที่มีการแข่งขันมากกว่าหนึ่งรายการ
Coderama

1
สิ่งนี้ดีกว่าการสร้างแฮชใหม่ทั้งหมด (โดยการโทรinvert) เพียงเพื่อค้นหารายการ
Hejazi

3
โปรดทราบว่าในฐานะของRuby 1.9.3สิ่งนี้จะส่งคืนแฮชใหม่ที่มีการแข่งขัน มันจะไม่กลับอาร์เรย์ที่มันใช้ในการในรูบี <= 1.8.7 clients.select{|key, hash| hash["client_id"] == "2180" } # => {"orange"=>{"client_id"=>"2180"}}
AndrewS

ในการรับกุญแจเพียงใส่clients.select{|key, hash| hash["client_id"] == "2180" }.keys
Mirror318

407

Ruby 1.9และสูงกว่า:

hash.key(value) => key

ทับทิม 1.8 :

คุณสามารถใช้ hash.index

hsh.index(value) => key

ส่งคืนคีย์สำหรับค่าที่กำหนด nilหากไม่พบผลตอบแทน

h = { "a" => 100, "b" => 200 }
h.index(200) #=> "b"
h.index(999) #=> nil

เพื่อให้ได้"orange"คุณสามารถใช้:

clients.key({"client_id" => "2180"})

2
นี้จะได้รับชนิดของยุ่งถ้า hashes indexมีหลายคีย์เพราะคุณจะต้องให้กัญชาทั้งหมด
Daniel Vandersluis

51
Hash#indexถูกเปลี่ยนชื่อเป็นHash#keyใน Ruby 1.9
Vikrant Chaudhary

12
โปรดทราบว่าสิ่งนี้จะส่งคืนการจับคู่ครั้งแรกเท่านั้นหากมีการจับคู่แฮชหลายอันที่มีค่าเท่ากันมันจะส่งคืนคีย์แรกพร้อมค่าที่ตรงกัน
Mike Campbell

47

คุณสามารถสลับแฮช clients.invert["client_id"=>"2180"]ผลตอบแทน"orange"


3
นี่ก็ดูเหมือนเป็นวิธีที่ฉลาด (เพราะมันสั้น) ที่จะทำ!
Coderama

นี่คือสิ่งที่ฉันต้องการสำหรับแบบฟอร์มอาร์เรย์ (สำหรับกล่องที่เลือก) ซึ่งสร้างแฮชย้อนหลัง
Joseph Le Brech

22

คุณสามารถใช้ hashname.key (ชื่อค่า)

หรือการผกผันอาจเป็นไปตามลำดับ new_hash = hashname.invertจะให้สิ่งnew_hashที่ช่วยให้คุณทำสิ่งต่าง ๆ ได้มากกว่าเดิม


3
นี่เป็นวิธีการที่เหมาะสมใน Ruby รุ่นล่าสุด (1.9+)
Lars Haugseth

#invertเป็นความคิดที่ไม่ดีจริงๆในกรณีนี้เนื่องจากคุณได้จัดสรรหน่วยความจำสำหรับวัตถุแฮชที่ใช้แล้วเพื่อค้นหาคีย์ ขึ้นอยู่กับขนาดแฮชที่มีผลกระทบต่อประสิทธิภาพการทำงานอย่างรุนแรง
Dr.Strangelove

15

ลองนี้:

clients.find{|key,value| value["client_id"] == "2178"}.first

4
สิ่งนี้จะทำให้เกิดข้อยกเว้นถ้าการค้นหาส่งคืนค่าศูนย์เนื่องจากคุณไม่สามารถเรียก. first on ศูนย์ได้
Schrockwell

1
หากใช้ Rails คุณสามารถใช้.try(:first)แทน.firstเพื่อหลีกเลี่ยงข้อยกเว้น (หากคุณคาดว่าจะเป็นไปได้ที่ค่าจะหายไป)
aaron-coding

2
ในRuby 2.3.0 +คุณสามารถใช้เนวิเกเตอร์ &.firstที่ปลอดภัยในตอนท้ายของบล็อกเพื่อป้องกันการยกเว้น Nil
Gagan Gami


6

จากเอกสาร:

  • (Object?) ตรวจจับ (ifnone = nil) {| obj | ... }
  • (Object?) find (ifnone = nil) {| obj | ... }
  • (วัตถุ) ตรวจจับ (ifnone = nil)
  • (วัตถุ) ค้นหา (ifnone = nil)

ส่งผ่านแต่ละรายการเป็น enum เพื่อบล็อก ส่งคืนบล็อกแรกที่ไม่ใช่เท็จ หากไม่มีวัตถุที่ตรงกันให้เรียก ifnone และส่งคืนผลลัพธ์เมื่อมีการระบุหรือคืนค่าเป็นศูนย์

หากไม่มีการกำหนดบล็อกตัวแจงนับจะถูกส่งคืนแทน

(1..10).detect  {|i| i % 5 == 0 and i % 7 == 0 }   #=> nil
(1..100).detect {|i| i % 5 == 0 and i % 7 == 0 }   #=> 35

สิ่งนี้ใช้ได้กับฉัน:

clients.detect{|client| client.last['client_id'] == '2180' } #=> ["orange", {"client_id"=>"2180"}] 

clients.detect{|client| client.last['client_id'] == '999999' } #=> nil 

ดู: http://rubydoc.info/stdlib/core/1.9.2/Enumerable#find-instance_method


3

วิธีที่ดีที่สุดในการค้นหาคีย์สำหรับค่าเฉพาะคือการใช้เมธอดที่พร้อมใช้งานสำหรับแฮช ....

gender = {"MALE" => 1, "FEMALE" => 2}
gender.key(1) #=> MALE

ฉันหวังว่ามันจะแก้ปัญหาของคุณ ...


2

อีกวิธีที่ฉันจะลองคือใช้ #map

clients.map{ |key, _| key if clients[key] == {"client_id"=>"2180"} }.compact 
#=> ["orange"]

สิ่งนี้จะส่งคืนค่าทั้งหมดที่เกิดขึ้น เครื่องหมายขีดล่างหมายความว่าเราไม่จำเป็นต้องดำเนินการกับค่าของคีย์ดังนั้นวิธีนั้นจึงไม่ได้ถูกกำหนดให้กับตัวแปร อาร์เรย์จะมีนิลหากค่าไม่ตรงกันนั่นคือสาเหตุที่ฉันใส่#compactท้าย


1

นี่เป็นวิธีง่ายๆในการหากุญแจของค่าที่กำหนด:

    clients = {
      "yellow"=>{"client_id"=>"2178"}, 
      "orange"=>{"client_id"=>"2180"}, 
      "red"=>{"client_id"=>"2179"}, 
      "blue"=>{"client_id"=>"2181"}
    }

    p clients.rassoc("client_id"=>"2180")

... และเพื่อค้นหาค่าของคีย์ที่ระบุ:

    p clients.assoc("orange") 

มันจะให้คุณคู่ค่าคีย์

โดยการใช้ไซต์ของเรา หมายความว่าคุณได้อ่านและทำความเข้าใจนโยบายคุกกี้และนโยบายความเป็นส่วนตัวของเราแล้ว
Licensed under cc by-sa 3.0 with attribution required.