2017-09-25 1 views
1

함수가 List와 TreeSet간에 스칼라에서 다르게 작동하는 것으로 보이는 이상한 경우가 발생했습니다. 이유 또는 해결 방법이 확실하지 않습니다.Lists 및 TreeSet에서 다른 동작을하는 Contains()

간결하게하기 위해 DataStructure이라는 클래스를 만들었습니다. 두 요소가 있습니다. 좌표 쌍 (i, j)Int입니다. (이보다 더 복잡하지만이 MWE에서는 이것이 보입니다.) Int으로 정렬 할 사용자 지정 비교기가 있으며 hashCodeequals을 오버라이드하여 동일한 좌표 쌍 (i, j)을 포함하는 두 요소가 처리됩니다 Int에 관계없이 동등한 것으로 간주됩니다.

DataStructure의 인스턴스를 ListTreeSet에 넣으면 프로그램에서 정확하게 일치하는 항목을 찾을 수 있습니다. 그러나 동일한 좌표 쌍을 가지지 만 다른 Int과 다른 요소를 확인하면 List.containstrue을 반환하고 TreeSet.containsfalse을 반환합니다. 왜 이런 일이 일어나고 어떻게 해결할 수 있습니까?

는 내 코드는 최소 동작하는 예제로 감소된다 :

클래스 DataStructure

package foo 

class DataStructure(e1: (Int, Int), e2: Int) extends Ordered[DataStructure] { 
    val coord: (Int, Int) = e1 
    val cost: Int = e2 

    override def equals(that: Any): Boolean = { 
    that match { 
    case that: DataStructure => if (that.coord.hashCode() == this.coord.hashCode()) true else false 
    case _ => false 
    }} 
    override def hashCode(): Int = this.coord.hashCode() 

    def compare(that: DataStructure) = { 
    if (this.cost == that.cost) 
     0 
    else if (this.cost > that.cost) 
     -1 //reverse ordering 
    else 
     1 
    }  
} 

드라이버 프로그램

package runtime 

import foo.DataStructure 
import scala.collection.mutable.TreeSet 

object Main extends App { 
     val ts = TreeSet[DataStructure]() 

     val a = new DataStructure((2,2), 2) 
     val b = new DataStructure((2,3), 1) 

     ts.add(a) 
     ts.add(b) 

     val list = List(a, b) 

     val listRes = list.contains(a) // true 
     val listRes2 = list.contains(new DataStructure((2,2), 0)) // true 
     val tsRes = ts.contains(a) // true 
     val tsRes2 = ts.contains(new DataStructure((2,2), 0)) // FALSE! 

     println("list contains exact match: " + listRes) 
     println("list contains match on first element: " + listRes2) 
     println("TreeSet contains exact match: " + tsRes) 
     println("TreeSet contains match on first element: " + tsRes2) 
} 

출력 :

list contains exact match: true 
list contains match on first element: true 
TreeSet contains exact match: true 
TreeSet contains match on first element: false 
+2

당신은 이미 답을 가지고 있습니다,하지만 equals로 해시 코드를 사용하는 것은 다른 객체에 대해 동일한 해시 코드를 가질 수 있기 때문에 나쁜 아이디어라고 덧붙이고 싶습니다. – puhlen

답변

7

아르 모 확실하게 List.contains은 일치하는 것을 찾기 위해 각 요소에 대해 equals을 확인하는 반면 TreeSet.contains은 나무를 걷고 compare을 사용하여 일치하는 것을 찾습니다.

compare이 (가) equals과 일치하지 않습니다. 나는 당신이 그 일을하는 이유를 알고 있지만하지 않습니다. "주문의 인스턴스에 대한 equals 메소드는 [A]를 비교하는 방법과 일치하는 것이 중요하다"

https://www.scala-lang.org/api/current/scala/math/Ordered.html

+1

바닐라 자바에서도 equals와 compareTo 사이의 일관성은 equals와 hashCode 간의 일관성이 Object 계약의 일부이므로 Comparable 계약의 일부이므로이 경우 3이 일관되어야합니다. – cchantep

관련 문제