ruby散列中的交换键

ruby散列中的交换键,ruby,hash,hashmap,Ruby,Hash,Hashmap,在Ruby中,如何交换散列中的键 假设我有以下散列: {:one=>1, :two=>2, :three=>3, :four=>4 } 我想转化为: {:one=>1, :three=>2, :two=>3, :four=>4} 也就是说,交换键:2和:3,但保持其值不变 最有效的解决方案是什么?哈希中没有顺序的概念。最简单的方法是: h = {:one => 1, :two => 2, :three => 3, :four

在Ruby中,如何交换散列中的键

假设我有以下散列:

{:one=>1, :two=>2, :three=>3, :four=>4 }
我想转化为:

{:one=>1, :three=>2, :two=>3, :four=>4}
也就是说,交换键:2和: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记住哈希的插入顺序,所以
值总是以原始顺序返回。如果您希望在不依赖插入顺序的情况下执行此操作,那么这只是一个小改动:

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-de1
DB%hash=('1'=>1,'2'=>2,'3'=>3,'4'=>4)
DB x\%hash
0哈希(0x7fceb94afce8)
“四”=>4
“一”=>1
“三”=>3
“两个”=>2
DB@hash{'1','3','2','4'}=@hash{'1','2','3','4'}
DB x\%hash
0哈希(0x7fceb94afce8)
“四”=>4
“一”=>1
“三”=>2
“两个”=>3

基本上,Perl能够通过将哈希强制到数组并定义键的顺序来检索或分配与Ruby的
values_at
相当的值。在Perl中,当您需要重新构造大量数据时,它是一个功能强大的工具。

保持顺序重要吗?如果没有,只需交换值即可。请解释请求背后的原因。保持顺序很重要。在实际情况中,运行mssql存储过程后,我会得到一个集合(哈希数组),然后由助手将其表示为html表。我需要更改几列的顺序。但是,由于Ruby 1.9,Ruby保持了插入顺序,所以以前是这样。“不过这不是一个排序的散列。@theTinMan我说的不是Ruby,而是散列语义。的确,实现可能有顺序的概念,但是这不是您应该构建的基础。实际上,我们保证Ruby的哈希插入顺序将得到维护。这在它第一次实现的时候被讨论了很多。其他语言可能会做一些不同的事情,但我们这里讨论的是Ruby。我同意,利用散列中键的顺序是相当危险的(特别是如果它被保存在db中)。不幸的是,问题是关于另一件事。前两行+1。(我想您可以跳过其他部分)。在使用“代码>注销< /代码>的情况下,您可以考虑使用,而不是<代码>注销< /代码>,您需要将对象(这里是哈希)返回到块结束时的迭代器。这对于
每个带有对象的\u
来说是不必要的。每天学习新东西:)我甚至不知道
每个带有对象的\u
,尽管我偶尔会梳理
可枚举的方法来提醒自己。非常感谢你完整的回答@migimunz,用swap扩展哈希类!和交换方法在我的情况下做了一个窍门。想到一个办法是使用<代码> EhcIO.Objult<代码>,每当代码>注销< /代码>的参数将是<代码> {} <代码>或<代码> []/Cord>。Wastrox,如果你使用Ruby 2,你可能想考虑使用,而不是改变类<代码>散列全局。有关
优化的详细信息