簡體   English   中英

將哈希數組轉換為散列哈希值,由哈希值的屬性索引

[英]Convert array-of-hashes to a hash-of-hashes, indexed by an attribute of the hashes

我有一個表示對象的哈希數組作為對API調用的響應。 我需要從一些哈希中提取數據,並且一個特定的鍵用作哈希對象的id。 我想將數組轉換為哈希,鍵為ids,值為原始哈希值。

這就是我所說的:

api_response = [
  { :id => 1, :foo => 'bar' },
  { :id => 2, :foo => 'another bar' },
  # ..
]

ideal_response = {
  1 => { :id => 1, :foo => 'bar' },
  2 => { :id => 2, :foo => 'another bar' },
  # ..
}

我有兩種方法可以想到這樣做。

  1. 將數據映射到ideal_response (下面)
  2. 使用api_response.find { |x| x[:id] == i } api_response.find { |x| x[:id] == i }我需要訪問的每條記錄。
  3. 我不知道的一種方法,可能涉及一種使用map來構建哈希的方法。

我的映射方法:

keys = data.map { |x| x[:id] }
mapped = Hash[*keys.zip(data).flatten]

我不禁感到有一種更高效,更整潔的方式。 當需要訪問的記錄數量非常少時,選項2非常高效。 映射優於此處,但當響應中有大量記錄時,它會開始崩潰。 值得慶幸的是,我不希望有超過50-100條記錄,因此映射就足夠了。

在Ruby中有更聰明,更整潔或更高效的方法嗎?

Ruby <= 2.0

> Hash[api_response.map { |r| [r[:id], r] }]
#=> {1=>{:id=>1, :foo=>"bar"}, 2=>{:id=>2, :foo=>"another bar"}} 

但是, Hash :: []非常丑陋,打破了通常從左到右的OOP流程。 這就是為什么Facets提出了Enumerable #mash

> require 'facets'
> api_response.mash { |r| [r[:id], r] }
#=> {1=>{:id=>1, :foo=>"bar"}, 2=>{:id=>2, :foo=>"another bar"}} 

這個基本的抽象(將枚舉變為哈希)被要求在很久以前被包含在Ruby中,唉, 沒有運氣

Ruby> = 2.1

[更新]仍然不喜歡Enumerable#mash #mash ,但現在我們有陣列#to_h 不理想 - 因為我們需要一個中間陣列 - 但總比沒有好:

> object = api_response.map { |r| [r[:id], r] }.to_h

為此,我可能會去:

ideal_response = api_response.each_with_object(Hash.new) { |o, h| h[o[:id]] = o }

塊中的多個括號不是很漂亮,但只需一次api_response迭代即可完成。

就像是:

ideal_response = api_response.group_by{|i| i[:id]} 
#=> {1=>[{:id=>1, :foo=>"bar"}], 2=>[{:id=>2, :foo=>"another bar"}]}

它使用Enumerable的group_by ,它適用於集合,返回所需鍵值的匹配。 因為它期望找到多次匹配的鍵值命中,所以它將它們附加到數組,因此最終得到哈希數組的哈希值。 如果需要,可以剝離內部數組,但如果兩個哈希ID發生沖突,可能會有覆蓋內容的風險。 group_by避免使用內部數組。

訪問特定元素很簡單:

ideal_response[1][0]       #=> {:id=>1, :foo=>"bar"}
ideal_response[1][0][:foo] #=> "bar"

您在問題結尾處顯示的方式是另一種有效的方法。 兩者都相當快速和優雅。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM