【问题标题】:compare two arrays except element x,y,z (ruby)比较两个数组,除了元素 x,y,z (ruby)
【发布时间】:2010-03-03 03:14:05
【问题描述】:

还有其他simple,nicer的方式吗?

require 'pp'

a1 = ["02/28/10","Webinars","131","0","26 Feb 2010","0","3d, 8h, 49m, 18s"]
a2 = ["02/20/10","Webinars","131","9","26 Feb 2010","0","3d, 8h, 49m, 18s"]

def compare(array1,array2,ignore)

  tmp1 = Array.new
  tmp2 = Array.new
  0.upto(array1.length-1) {|index|
    if !ignore.include?(index)
      tmp1 << array1[index]
      tmp2 << array2[index]
    end
  }
  if tmp1 == tmp2 
    return true
  else
    return false    
  end
end

pp a1
pp a2
puts
puts compare(a1,a2,[0,3])

输出是

["02/28/10", "Webinars", "131", "0", "26 Feb 2010", "0", "3d, 8h, 49m, 18s"]
["02/20/10", "Webinars", "131", "9", "26 Feb 2010", "0", "3d, 8h, 49m, 18s"]

true

【问题讨论】:

  • 仅供参考,问题中的版本始终返回 true,因为 tmp1 和 tmp2 指向同一个数组。尝试比较([0],[1],[])
  • 感谢您指出这一点。已修复。

标签: ruby arrays comparison


【解决方案1】:

最简单的代码(需要 Ruby 1.8.7 或更高版本):

def compare(array_a, array_b, ignore_list)
  array_a.zip(array_b).each_with_index.all? do |a, b, idx|
    a == b or ignore_list.include? idx
  end
end

我怀疑它也会更快(因为它使用单个 zip 而不是单独询问每个项目的数组)——尽管这可能不是速度很重要的情况。

顺便说一句,几乎任何时候我在 Ruby 中直接索引一个数组(如 some_array[i])而不是使用诸如 mapeach 之类的高阶方法时,我都认为这是一个标志我可能在标准库中遗漏了一些东西,并且该算法的效率可能会低于高度优化的库函数。

【讨论】:

  • 好一个。我在 Ruby 中忽略了zip。但是对于all?,带有 3 个参数的块来自哪里。下面的代码为我写了nil,这意味着a是一个元素,b是一个索引。 idx 未定义:[1,2].zip(['a', 'b']).each_with_index.all? { |a,b,idx| puts idx; true }
【解决方案2】:

可能有很多更简洁的方法可以做到这一点。这是我想到的第一个,我确信可以改进。

def compare(array1, array2, ignore)
  return false if array1.size != array2.size
  0.upto(array1.size) do |i|
    return false if !ignore.include?(i) && array1[i] != array2[i]
  end
  return true
end

本质上是手动数组比较。检查相同的大小,然后一一检查元素(但忽略我们被告知要忽略的索引)。一旦我们知道继续进行毫无意义,就立即休息。

【讨论】:

  • @Matchu:太好了!它工作得非常好:-) 只是让我了解你的代码的另一个澄清。一旦函数比较命中任何返回,它就不会继续运行代码而是退出函数。对吗?
  • 这是正确的 :) 一旦我们知道函数将返回什么,我不想再运行任何检查。
  • @Matchu:为什么“使用 do/end 而不是括号”?
  • @Radek,我会介意回答。这是 Ruby 中的通用约定:单行块使用 { },多行 - do end
  • 谢谢德米特里。每一天,每一天,人们都会学到一些新东西
【解决方案3】:

这对我来说看起来更好:):

def compare(array1, array2 = [], ignore = [])
  return false if array1.length != array2.length
  array1.each_with_index.all? do |e1, i1|
    array2[i1] == e1 || ignore.include?(i1)
  end
end

它的美妙之处在于它“链接”each_with_indexall?,使代码更简洁。
不好的是它只适用于 Ruby 1.8.7。无论如何都看不到使用 的理由

【讨论】:

  • 我不喜欢这会改变原始数组。
  • @Dmitriy Nagirnyak:你的代码给了我一个错误 `each_with_index': no block given (LocalJumpError) 但最重要的是我已经尝试过了。 delete_at(i) 导致忽略数组中的第二个元素将不正确,因为索引会更改。它还将修改作为参数传递的原始数组。当然我可以使用一些 tmp 数组。
  • 不小心撤销了downvote;希望我能把它放回去。这会在 compare([1,2],[1,2,3],[]) 上返回误报
  • 我已经更新了不改变数组的答案。它对我有用(Ruby 1.8.7)。数组[1,2][1,2,3] 不应该相等。当前方法不检查(如果需要,很容易做到,但我没有观察到这样的要求)。反正我会更新的。
  • 对。运行compare([1,2],[1,2,3],[])的这个定义,显然应该是假的,它返回true
【解决方案4】:

这个怎么样?

require 'enumerator'
def compare (a1, a2, i)
  a1.size == a2.size and
    ( a1.enum_for(:each_with_index).select{ |v, j| !i.include?(j)} ==
      a2.enum_for(:each_with_index).select{ |v, j| !i.include?(j)} )

end

compare([1,2,3,4,5], [1,7,6,4,5], [1,2]) #true
compare([1,2,3,4,5], [1,7,6,4,5], [1,2]) #true

注意 这将适用于 Ruby 1.8.6。你可以使用Dmitriy Nagirnyak的方法进一步优化:

def compare (a1, a2, i)
  a1.size == a2.size and
    a1.enum_for(:each_with_index).all?{|v, j| a2[j] == v or i.include?(j)}
end

【讨论】:

  • 你需要什么值?如果您希望它在匹配时为假,则否定结果。
  • 当数组有重复值时不起作用。让我解决它。
  • 我已经修正了逻辑。看看吧。
  • 现在它给了我undefined method enum_for for #&lt;Array:0x2c33398&gt; (NoMethodError)
  • 您需要require 'enumerator'。我已将其添加到代码中。
【解决方案5】:

这是 1.9 的解决方案,它比较 以及 == 的数组:

#!/usr/bin/ruby1.9

# Return -1 if array1 < array2
#         0 if array1 == array2
#        +1 if array1 > array2
# ignore contains indices of elements to ignore

def compare(array1, array2, ignore)
  filter = lambda do |a|
    a.collect.with_index do |e, i|
      if ignore.include?(i)
        ''
      else
        e
      end
    end
  end
  filter[array1] <=> filter[array2]
end

array1 = ["02/28/10","Webinars","131","0","26 Feb 2010","0","3d, 8h, 49m, 18s"]
array2 = ["02/20/10","Webinars","131","9","26 Feb 2010","0","3d, 8h, 49m, 18s"]

p compare(array1, array2, [0, 3])    # => 0
p compare(array1, array2, [0])       # => -1
p compare(array1, array2, [3])       # => 1

【讨论】:

    【解决方案6】:

    这是另一个,简洁且效率极低:

    def compare a1, a2, i
      [a1,a2].map { |a|
        a.values_at(*((0...a.length).to_a - i))
      }.inject(&:==)
    end
    

    【讨论】:

      猜你喜欢
      • 2020-01-20
      • 1970-01-01
      • 1970-01-01
      • 2013-02-26
      • 2016-06-19
      • 2017-08-19
      • 1970-01-01
      • 1970-01-01
      • 2021-05-06
      相关资源
      最近更新 更多