[英]Swap keys in ruby hash
在Ruby中,如何交換哈希中的密鑰?
假設我有以下哈希:
{:one=>1, :two=>2, :three=>3, :four=>4 }
我想轉化為:
{:one=>1, :three=>2, :two=>3, :four=>4}
即,交換鍵:two和:3,但其值保持不變。
最有效的解決方案是什么?
最簡單的方法是:
h = {:one => 1, :two => 2, :three => 3, :four => 4}
h[:two], h[:three] = h[:three], h[:two]
如果您需要定期執行此操作,則可以在Hash上定義一個允許使用更漂亮語法的方法:
class Hash
def swap!(a, b)
self[a], self[b] = self[b], self[a] if key?(a) && key?(b)
self
end
def swap(a, b)
self.dup.swap!(a, b)
end
end
但請注意,這兩種解決方案都將保留散列中鍵值對的順序。 如果要實際交換密鑰及其值,可以執行以下操作:
class Hash
def swap(a, b)
self.inject(Hash.new) do |h, (k,v)|
if k == a
h[b] = self[a]
elsif k == b
h[a] = self[b]
else
h[k] = v
end
h
end
end
end
{:one => 1, :two => 2, :three => 3, :four => 4}.swap(:two, :three)
# results in {:one=>1, :three=>2, :two=>3, :four=>4}
雖然我不確定您為什么要這么做。
Perl確實很容易做到這一點,但是Ruby沒有哈希切片,因此我們必須以一種更簡單的方式進行:
hash = {:one=>1, :two=>2, :three=>3, :four=>4 }
new_key_order = [:one, :three, :two, :four]
new_hash = Hash[new_key_order.zip(hash.values)]
# => {:one=>1, :three=>2, :two=>3, :four=>4}
之所以可行,是因為Ruby記住了哈希的插入順序,因此values
始終按原始順序返回它們。 如果您想在不依賴於廣告訂單的情況下執行此操作,則只需進行一些小改動:
old_key_order = [:one, :two, :three, :four]
new_key_order = [:one, :three, :two, :four]
new_hash = Hash[new_key_order.zip(hash.values_at(*old_key_order))]
# => {:one=>1, :three=>2, :two=>3, :four=>4}
注意,我對齊了鍵的列,以使更改真正突出。 當代碼中的某些變化看起來非常相似時,我們將在團隊中這樣做,以使其顯而易見。
可以使用並行分配,但是當您處理許多列或字段時,這確實會很快使混亂的代碼加起來。 像上面那樣定義輸入順序和輸出順序更容易,因此您對映射有非常直觀的參考,然后將它們傳遞給zip
並讓它完成艱苦的工作,然后將其強制返回到哈希中。
順便說一句,這就是我在Perl中的做法。 這是使用調試器:
perl -de 1
DB<1> %hash = ('one' => 1, 'two' => 2, 'three' => 3, 'four' => 4)
DB<2> x \%hash
0 HASH(0x7fceb94afce8)
'four' => 4
'one' => 1
'three' => 3
'two' => 2
DB<3> @hash{'one', 'three', 'two', 'four'} = @hash{'one', 'two', 'three', 'four'}
DB<4> x \%hash
0 HASH(0x7fceb94afce8)
'four' => 4
'one' => 1
'three' => 2
'two' => 3
基本上,Perl可以通過將哈希強制轉換為數組並定義鍵的順序來檢索或分配與Ruby的values_at
等效的功能。 當你想要重構大量數據時,它是Perl中一個非常強大的工具。
散列中沒有順序概念。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.