Ruby'dagi ko'p o'lchovli qatorni Hashga aylantirish

Menda shunday bir narsa bor:

input = [['abc',['xyz','1.1']], ['abc',['xyz','1.2']],['def',['lmn','3.14']]]

Men buni aylantirishni istayman

{'abc'=>[{'xyz'=>'1.1'},{'xyz'=>'1.2'}],'def'=>[{'lmn'=>'3.14'}]}

Buning eng yaxshi yo'li qanday?

2
Iltimos, " Qanday so'raladi " bilan bog'langan sahifalar, "" Minimal, to'liq va tasdiqlangan misol "va" Stack Overflow Foydalanuvchilar? "Biz sizning harakatlaringizning dalillarini ko'rishni istaymiz, siz nimani sinab ko'rdingiz, hech narsa topmadingizmi va topmadingizmi? Siz narsalarni topdingizmi, lekin u yordam bermadi? yo'q bo'lsa, nega? Agar shunday bo'lsa, nima sinab ko'rganingizni ko'rsatadigan eng kichik kod misoli va nima uchun u ishlamayapti?
qo'shib qo'ydi muallif the Tin Man, manba

6 javoblar

every_with_object dan foydalanishingiz mumkin:

accumulator = Hash.new { |k,v| k[v] = [] }

input.each_with_object(accumulator) {|(f, s), memo| memo[f] << Hash[*s] }
#=> {"abc"=>[{"xyz"=>"1.1"}, {"xyz"=>"1.2"}], "def"=>[{"lmn"=>"3.14"}]}
8
qo'shib qo'ydi
@Raffael, albatta har bir dan foydalanishingiz mumkin, lekin bu akkumulyatorni qaytarmaydi. Misol uchun, agar siz uni metodda o'rab qo'yishingiz kerak bo'lsa, oxirgi qatorni akkumulyator bo'lishi kerak. each_with_object , aksincha, ob'ektni qaytaradi ( memo ). Bundan tashqari, akkumulyatori kodi har dan foydalanish bilan taqqoslaganda ikkita iboralarni saqlab qo'yishi va memo ko'lamini ham cheklashi mumkin.
qo'shib qo'ydi muallif Cary Swoveland, manba
Ha, har bir ga qo'ng'iroqdan so'ng natija batareyani da saqlanadi. Kechirasiz, bu ochiq-oydin edi. Natijani qaytarishni istasangiz, men haqiqatdan ham boshqa qatorni qo'shishingizni tavsiya qilaman. Men buni shaxsiy imtiyozlarsiz tavsiya qilaman. Qisqa kod orqali aniq va oson o'qilishi mumkin kodni afzal ko'raman.
qo'shib qo'ydi muallif Raffael, manba
Yaxshi javob. every_with_object har bir dan foydalanishingiz mumkin? Buni yodda tutgan narsa: input.each {| f, s | akkumulyator [f] << xash [* s]}
qo'shib qo'ydi muallif Raffael, manba

every_with_object dan foydalanishingiz mumkin:

accumulator = Hash.new { |k,v| k[v] = [] }

input.each_with_object(accumulator) {|(f, s), memo| memo[f] << Hash[*s] }
#=> {"abc"=>[{"xyz"=>"1.1"}, {"xyz"=>"1.2"}], "def"=>[{"lmn"=>"3.14"}]}
8
qo'shib qo'ydi
@Raffael, albatta har bir dan foydalanishingiz mumkin, lekin bu akkumulyatorni qaytarmaydi. Misol uchun, agar siz uni metodda o'rab qo'yishingiz kerak bo'lsa, oxirgi qatorni akkumulyator bo'lishi kerak. each_with_object , aksincha, ob'ektni qaytaradi ( memo ). Bundan tashqari, akkumulyatori kodi har dan foydalanish bilan taqqoslaganda ikkita iboralarni saqlab qo'yishi va memo ko'lamini ham cheklashi mumkin.
qo'shib qo'ydi muallif Cary Swoveland, manba
Ha, har bir ga qo'ng'iroqdan so'ng natija batareyani da saqlanadi. Kechirasiz, bu ochiq-oydin edi. Natijani qaytarishni istasangiz, men haqiqatdan ham boshqa qatorni qo'shishingizni tavsiya qilaman. Men buni shaxsiy imtiyozlarsiz tavsiya qilaman. Qisqa kod orqali aniq va oson o'qilishi mumkin kodni afzal ko'raman.
qo'shib qo'ydi muallif Raffael, manba
Yaxshi javob. every_with_object har bir dan foydalanishingiz mumkin? Buni yodda tutgan narsa: input.each {| f, s | akkumulyator [f] << xash [* s]}
qo'shib qo'ydi muallif Raffael, manba

Buning yana bir yo'li:

input.inject({}) { |a, (k, v)| a.merge(k => [Hash[*v]]) { |_, o, n| o + n } }

Ilya ta'kidlaganidek, birlashma! kodi birlashma dan afzalroq bo'lishi kerak, chunki u yaxshi ishlash ko'rsatkichlariga ega.

3
qo'shib qo'ydi
birlashma! yanada samarali bo'ladi.
qo'shib qo'ydi muallif Ilya, manba
Buni qanday qilish mumkin: input.inject ({}) {| a, (k, (ik, v)) | a.merge! (K => [{ik => {"value" => v}}]) {| _, u, n | u + n}} Lekin shubhasiz bu haqiqatan ham tezda juda murakkablashib bormoqda. Demak, agar siz faqat irbda ijro etishni xohlasangiz, men ayta oladigan o'zgaruvchan ismlarni ishlatishni taklif qilaman va shuning uchun tushunishni osonlashtiradigan qismlarga aylantira olaman.
qo'shib qo'ydi muallif kaikuchn, manba
@kaikuchn zo'r! Menda yana bitta narsa bor. Bunga qanday erishish mumkin? {'abc' => [{'xyz' => {'value' => 1.1 '}}, {"xyz" => {' value '=> 1.2'}}} & zwnj; '=> [{' lmn '=> {' va & zwnj; lue '=> 3.14'}}}}
qo'shib qo'ydi muallif Makoto Taguchi, manba

Buning yana bir yo'li:

input.inject({}) { |a, (k, v)| a.merge(k => [Hash[*v]]) { |_, o, n| o + n } }

Ilya ta'kidlaganidek, birlashma! kodi birlashma dan afzalroq bo'lishi kerak, chunki u yaxshi ishlash ko'rsatkichlariga ega.

3
qo'shib qo'ydi
birlashma! yanada samarali bo'ladi.
qo'shib qo'ydi muallif Ilya, manba
Buni qanday qilish mumkin: input.inject ({}) {| a, (k, (ik, v)) | a.merge! (K => [{ik => {"value" => v}}]) {| _, u, n | u + n}} Lekin shubhasiz bu haqiqatan ham tezda juda murakkablashib bormoqda. Demak, agar siz faqat irbda ijro etishni xohlasangiz, men ayta oladigan o'zgaruvchan ismlarni ishlatishni taklif qilaman va shuning uchun tushunishni osonlashtiradigan qismlarga aylantira olaman.
qo'shib qo'ydi muallif kaikuchn, manba
@kaikuchn zo'r! Menda yana bitta narsa bor. Bunga qanday erishish mumkin? {'abc' => [{'xyz' => {'value' => 1.1 '}}, {"xyz" => {' value '=> 1.2'}}} & zwnj; '=> [{' lmn '=> {' va & zwnj; lue '=> 3.14'}}}}
qo'shib qo'ydi muallif Makoto Taguchi, manba

Boshqa variant:

accumulated = {}

input.each { |k, v| accumulated[k]&.push(Hash[*v]) || accumulated[k] = [Hash[*v]] }

#=> accumulated
#=> {"abc"=>[{"xyz"=>"1.1"}, {"xyz"=>"1.2"}], "def"=>[{"lmn"=>"3.14"}]}

If you're using Rails, you can substitute the safe navigation operator (&) with try() if you find it to be more readable:

input.each { |k, v| accumulated[k].try(:push, Hash[*v]) || accumulated[k] = [Hash[*v]] }
1
qo'shib qo'ydi
Ushalar usuli qaerdan keladi? Hech qanday Hash yoki NilClass docsda belgilangan sinashga ega.
qo'shib qo'ydi muallif iain, manba
Iltimos, javobingizni o'zgartirganda "tahrirlangan" yoki "yangilangan" turdagi teglardan foydalanmang. Buning o'rniga ma'lumotni dastlab qo'ygan joyga qo'shib qo'ying. Biz nima o'zgarganini va kerak bo'lganda ham ko'rishimiz mumkin. meta.stackexchange.com/a/127655/153968" buni yaxshi tushuntiradi.
qo'shib qo'ydi muallif the Tin Man, manba
Oh derp - ha, afsuski, try aslida Rails usuli. Men shunga muvofiq javobni yangilayman.
qo'shib qo'ydi muallif jeffdill2, manba

Boshqa variant:

accumulated = {}

input.each { |k, v| accumulated[k]&.push(Hash[*v]) || accumulated[k] = [Hash[*v]] }

#=> accumulated
#=> {"abc"=>[{"xyz"=>"1.1"}, {"xyz"=>"1.2"}], "def"=>[{"lmn"=>"3.14"}]}

If you're using Rails, you can substitute the safe navigation operator (&) with try() if you find it to be more readable:

input.each { |k, v| accumulated[k].try(:push, Hash[*v]) || accumulated[k] = [Hash[*v]] }
1
qo'shib qo'ydi
Ushalar usuli qaerdan keladi? Hech qanday Hash yoki NilClass docsda belgilangan sinashga ega.
qo'shib qo'ydi muallif iain, manba
Iltimos, javobingizni o'zgartirganda "tahrirlangan" yoki "yangilangan" turdagi teglardan foydalanmang. Buning o'rniga ma'lumotni dastlab qo'ygan joyga qo'shib qo'ying. Biz nima o'zgarganini va kerak bo'lganda ham ko'rishimiz mumkin. meta.stackexchange.com/a/127655/153968" buni yaxshi tushuntiradi.
qo'shib qo'ydi muallif the Tin Man, manba
Oh derp - ha, afsuski, try aslida Rails usuli. Men shunga muvofiq javobni yangilayman.
qo'shib qo'ydi muallif jeffdill2, manba