删除ruby中数组中的类似元素

时间:2013-04-21 10:59:42

标签: ruby arrays swap

我有以下数组

a3 = [["a", "b"], ["a","c"], ["b","c"], ["b", "a"], ["c","b"]]

我想获得以下输出[["a","b"], ["a","c"], ["b","c"]]并删除["b","a"] and ["c","b"]

我有以下代码

a3.each do |ary3|
x = ary3[0]
y = ary3[1]
x = ary3[1]
y = ary3[0]
if a3.include?([x,y])
   a3 - [y,x]
   end
end
print a3

我尝试使用交换,但没有运气!

感谢您的帮助。

2 个答案:

答案 0 :(得分:6)

如果两个数组包含相同的元素并且这些元素的顺序相同,则认为它们是相等的:

["a", "b"] == ["b", "a"]
#=> false

["a", "b"] == ["a", "b"]
#=> true

因此,您需要先对内部数组进行排序,然后使用Array#uniq确保外部数组中的每个元素只出现一次:

arr = [["a", "b"], ["a", "c"], ["b", "c"], ["b", "a"], ["c", "b"]]
arr.map(&:sort).uniq
#=> [["a", "b"], ["a", "c"], ["b", "c"]]

然而,这将使arr保持不变:

arr
#=> [["a", "b"], ["a", "c"], ["b", "c"], ["b", "a"], ["c", "b"]]

您需要使用mutator方法(使用!)来编辑数组:

arr = [["a", "b"], ["a", "c"], ["b", "c"], ["b", "a"], ["c", "b"]]
arr.map!(&:sort).uniq!
arr
#=> [["a", "b"], ["a", "c"], ["b", "c"]]

修改

作为@sawa评论的后续行动,谁担心改变内部数组的顺序可能不合适,我看起来更深入Array#uniq。请考虑以下数组:

arr = [["b", "a"], ["a", "c"], ["b", "c"], ["b", "a"], ["c", "b"]]

我发现Array#uniq实际上需要一个块来指定元素应该如何比较:

arr.uniq!{|x| x.sort }
arr
#=> [["b", "a"], ["a", "c"], ["b", "c"]]

很酷的是,这也适用于Symbol#to_proc&:符号),实际上看起来比我原来的答案更优雅:

arr.uniq!(&:sort)
arr
#=> [["b", "a"], ["a", "c"], ["b", "c"]]

如果您希望事后对内部数组进行排序,您仍然可以使用Array#sort!

arr.uniq!(&:sort!)
arr
#=> [["a", "b"], ["a", "c"], ["b", "c"]]

我对此的最后一个观察是,顺序可能并不重要,否则两个不同顺序的数组将被视为不相等。这让我思考(再次),我自己提出了一个问题:为什么不使用Set?它会像这样工作:

require 'set'

sets = [Set["a", "b"], Set["a", "c"], Set["b", "c"], Set["b", "a"], Set["c", "b"]]
sets.uniq!
sets
#=> [#<Set: {"a", "b"}>, #<Set: {"a", "c"}>, #<Set: {"b", "c"}>]

请记住,Set不允许多次添加相同的元素,而数组则会:

[%w[a b b b c], %w[a b b b c], %w[a b c]].uniq(&:sort)
#=> [["a", "b", "b", "b", "c"], ["a", "b", "c"]]

[Set.new(%w[a b b b c]), Set.new(%w[a b b b c]), Set.new(%w[a b c])].uniq
#=> [#<Set: {"a", "b", "c"}>]

答案 1 :(得分:0)

检查一下:#delete_if如下:

a3 = [["a", "b"], ["a","c"], ["b","c"], ["b", "a"], ["c","b"]]
p a3.delete_if{|x| [["b", "a"], ["c","b"]].include? x}
#=> [["a", "b"], ["a", "c"], ["b", "c"]]

根据您的评论和说明帖子:

a3 = [["a", "b"], ["a","c"], ["b","c"], ["b", "a"], ["c","b"],["b", "a"]]
p a3.each {|x| a3.delete(x.reverse) if a3.include? x.reverse}
#=> [["a", "b"], ["a", "c"], ["b", "c"]]

基准:

require 'benchmark'
N = 10000


Benchmark.bm(20) do | x |
  a3 = [["a", "b"], ["a","c"], ["b","c"], ["b", "a"], ["c","b"],["b", "a"]]
  x.report('Mine') do
    N.times { a3.each {|x| a3.delete(x.reverse) if a3.include? x.reverse} }
  end
  a3 = [["a", "b"], ["a","c"], ["b","c"], ["b", "a"], ["c","b"],["b", "a"]]
  x.report('padde') do
    N.times { a3.uniq!(&:sort!) }
  end

end

输出:

                           user     system      total        real

Mine                   0.172000   0.000000   0.172000 (  0.361021)
padde                  0.203000   0.000000   0.203000 (  0.460026)