开发者

compare two arrays except element x,y,z (ruby)

is there any other simple,nicer way?

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])

and the开发者_运维百科 output is

["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


Simplest code (requires Ruby 1.8.7 or above):

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

I suspect it will be faster, too (since it uses a single zip rather than individually asking the array for each item) — though this probably isn't a case where speed matters greatly.

As an aside, almost any time I'm directly indexing an array (like some_array[i]) in Ruby rather than using a higher-order method such as map or each, I take that as a sign that I'm probably missing something in the standard library and the algorithm will probably be less efficient than the highly optimized library function.


There are probably plenty of more concise ways of doing this. Here's the first that came to my mind, which I'm sure could be improved upon.

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

Essentially, a manual array comparison. Check for same size, then check the elements one by one (but ignoring indices we are told to ignore). Break as soon as we know it's pointless to proceed.


This looks better to me :) :

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

The beauty of this is that it "chains" each_with_index with all? making much cleaner code.
The bad is that it only works from Ruby 1.8.7. Anyway do not see a reason to use < 1.8.7


How about this?

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

Note This will work in Ruby 1.8.6. You can use Dmitriy Nagirnyak's method to optimize this further:

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


Here's a solution for 1.9 that compares the arrays for < and > as well as ==:

#!/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


Here's another one, terse and highly inefficient:

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

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜