halostatue / diff-lcs

Generate difference sets between Ruby sequences.
http://halostatue.github.com/diff-lcs
Other
290 stars 57 forks source link

Incorrect results when Enumerable contains generic objects. String collections works. #35

Closed tomasjura closed 4 years ago

tomasjura commented 9 years ago

When comparing collection (Enumerable) of objects which are not Strings, then result is incorrect. See attached example.

lcs_test1.rb.txt

jagdeepsingh commented 6 years ago

Pasting code and return values from link mentioned in the description:

require 'diff/lcs'

class M
  attr_reader :m

  def initialize(m)
    @m=m
  end

  def ==( o )
    o.m == @m
  end

  def hash
    @m.hash
  end

  def to_s
    return @m.to_s
  end    
end

s1 = %w(ma be c   e h j   l m      n po)
  => ["ma", "be", "c", "e", "h", "j", "l", "m", "n", "po"]

s2 = %w(ma be c d e f j k l m r s ta)
  => ["ma", "be", "c", "d", "e", "f", "j", "k", "l", "m", "r", "s", "ta"]

Diff::LCS::Internals.lcs(s1.map{ |s| M.new(s) } , s2.map { |s| M.new(s) })
  => [0, 1, 2]

Diff::LCS::Internals.lcs(s1, s2)
  => [0, 1, 2, 4, nil, 6, 8, 9]
timon commented 5 years ago

Struck me as well.

This is because the hash is used to map the objects to their positions.

mapping the strings to M objects ends up by instantiating different objects for the same string, and different slots are allocated in index hash for these objects.

The custom class should redefine eql? method to be an alias to == (in addition to custom == and hash methods) so that equal objects will use the same slot in hash.