簡體   English   中英

如何重構將此數組轉換為哈希值

[英]How can I refactor converting this array into a Hash

給定此數組(從文件生成)

["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"], 
["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"], 
["Camden", "DM1182", "54.64 USD"]]

我將它轉換為由第二個元素(sku)索引的哈希,代碼如下:

result = Hash.new([])
trans_data.each do |arr|
  result[arr[1]].empty? ? result[arr[1]] = [[arr[0], arr[2]]] : result[arr[1]] << [arr[0], arr[2]] 
end
result

這以我想要的格式輸出哈希:

{"DM1210"=>[["Yonkers", "70.00 USD"], ["Scranton", "68.76 USD"]], "DM1182"=>[["Yonkers", "19.68 AUD"], ["Nashua", "58.58 AUD"], ["Camden", "54.64 USD"]]}

我不覺得我的代碼是......干凈。 有沒有更好的方法來實現這一目標?

編輯:到目前為止,我能夠用:( (result[arr[1]] ||= []) << [arr[0], arr[2]]替換它

沒有哈希的默認值

看起來人們需要了解group_by

ary = [
  ["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"],
  ["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"],
  ["Camden", "DM1182", "54.64 USD"]
]
hash = ary.group_by{ |a| a.slice!(1) }

結果如下:

=> {"DM1210"=>[["Yonkers", "70.00 USD"], ["Scranton", "68.76 USD"]], "DM1182"=>[["Yonkers", "19.68 AUD"], ["Nashua", "58.58 AUD"], ["Camden", "54.64 USD"]]}

沒有slice!可以相當簡潔地寫出這個slice! ,允許ary保持不變,無需引入任何額外的類或模塊:

irb(main):036:0> Hash[ary.group_by{ |a| a[1] }.map{ |k, v| [k, v.map{ |a,b,c| [a,c] } ] }]
=> {"DM1210"=>[["Yonkers", "70.00 USD"], ["Scranton", "68.76 USD"]], "DM1182"=>[["Yonkers", "19.68 AUD"], ["Nashua", "58.58 AUD"], ["Camden", "54.64 USD"]]}
irb(main):037:0> ary
=> [["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"], ["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"], ["Camden", "DM1182", "54.64 USD"]]

其他幾個答案正在使用each_with_object ,這消除了使用Hash[...]將返回的數組強制轉換為哈希的需要。 下面是我如何使用each_with_object來避免塊中的一堆線路噪聲,因為它們嘗試初始化未知密鑰:

ary.each_with_object(Hash.new{ |h,k| h[k] = [] }) { |(a, b, c), h| 
  h[b] << [a, c] 
}
=> {"DM1210"=>[["Yonkers", "70.00 USD"], ["Scranton", "68.76 USD"]], "DM1182"=>[["Yonkers", "19.68 AUD"], ["Nashua", "58.58 AUD"], ["Camden", "54.64 USD"]]}

這利用了Hash.new采用初始化塊,當先前未定義某個鍵時,該初始化塊被調用。

使用抽象的功能方法來自Facets的Enumerable#map_by

require 'facets'
records.map_by { |name, key, price| [key, [name, price]] }
#=> {"DM1210"=>[["Yonkers", "70.00 USD"], ... }

遺憾的是Ruby沒有在核心內發布map_by ,它是一個非常有用的(因為它是未知的) Enumerable#group_by變體(你選擇分組鍵要累積的值)。

關於什么

result = trans_data.each_with_object({}) do |arr, hash|
  (hash[arr[1]] ||= []) << [arr[0], arr[2]]
end

注意:接受的答案是最好的答案,但我真的很高興我使用的奇怪的真棒和我如何解釋它:

arr = [["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"], 
["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"], 
["Camden", "DM1182", "54.64 USD"]]
 arr.each_with_object({}){|(a, b, c), hash| (hash[b] || hash[b]=[]).push [a,c]}

every_with_object為老上帝的道具!

說明:這里有兩個古怪的事情。 第一個, (a, b, c)魔法,我認為它的工作原理如下:

( 

  #This bit:
  arr.collect{|(a,b,c)| "#{a}#{b}#{c}"}

) - (

  #Is equivalent to this bit:
  (0..arr.size).collect {|i|
    (a,b,c) = arr[i] #=> (a,b,c) = ["Yonkers", "DM1210", "70.00 USD"]
    "#{a}#{b}#{c}"
  }

  #as you can see, they generate identical arrays:
) == []

請注意,在某些情況下,您可以將parens視為隱式: arr.collect{|a, b, c| [a, b, c]} == arr arr.collect{|a, b, c| [a, b, c]} == arr

第二個古怪的事情:

(hash[b] || hash[b]=[]).push(...)

請記住,Ruby中的所有內容都是表達式和​​引用。

[

 (hash[:a] || "foo") == (nil || "foo"),
 (hash[:b]=[]) == [],
 (hash[:b]=[]) === hash[:b],
 (hash[:b] || "foo") == ([] || "foo"),

] == [true, true, true, true]

hash[b] ,當鍵不存在時,求值為nil (這是假的),所以我們計算並返回后半部分: hash[b]=[]返回賦值的值,即現在的數組由hash[b]引用,所以我們可以推進它, hash[b]將[仍然是]引用更新的數組。

:d

PS - 我認為,這是我第一次回答的Ruby問題,這是我第一次想到,更不用說能夠把評論變成代碼了,哦,我喜歡它嗎? 。 謝謝你的拼圖!

試試這個

arr = [["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"], ["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"], ["Camden", "DM1182", "54.64 USD"]] 

hash = Hash.new{|h,k| h[k] = []}

 arr.each{|a| hash[a[1]].push([a[0],a[2]])}


   hash => {"DM1210"=>[["Yonkers", "70.00 USD"], ["Scranton", "68.76 USD"]], "DM1182"=>[["Yonkers", "19.68 AUD"], ["Nashua", "58.58 AUD"], ["Camden", "54.64 USD"]]}

或多或少從facet庫 tokland中提取:

ary = [["Yonkers", "DM1210", "70.00 USD"], ["Yonkers", "DM1182", "19.68 AUD"], ["Nashua", "DM1182", "58.58 AUD"], ["Scranton", "DM1210", "68.76 USD"], ["Camden", "DM1182", "54.64 USD"]]

hash = {}
ary.each{ |a,b,c| (hash[b] ||= []) << [a,c] }

hash
# => {"Camden"=>[["DM1182", "54.64 USD"]], "Nashua"=>[["DM1182", "58.58 AUD"]], "Scranton"=>[["DM1210", "68.76 USD"]], "Yonkers"=>[["DM1210", "70.00 USD"], ["DM1182", "19.68 AUD"]]}

暫無
暫無

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

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