在Ruby中,如何在Hash中交换密钥?
假设我有以下哈希:
{:one=>1, :two=>2, :three=>3, :four=>4 }
我想转变为:
{:one=>1, :three=>2, :two=>3, :four=>4}
,交换键:两个和:三个但保持其值不变。
对此最有效的解决方案是什么?
答案 0 :(得分:5)
最简单的方法是:
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}
虽然我不确定你为什么要那样做。
答案 1 :(得分:1)
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中一个非常强大的工具。
答案 2 :(得分:-1)
散列中没有顺序概念。