关于 scala:返回类型不同的元素 ((String,String) , Double)

Returning distinct elements of type ((String,String) , Double)

1
2
3
4
val v : Array[((String, String), Double)] = Array( ( ("a" ,"b") , 1.0) , (("b" ,"a") , 1.0) )
                                                  //> v  : Array[((String, String), Double)] = Array(((a,b),1.0), ((b,a),1.0))

  val d = v.distinct                              //> d  : Array[((String, String), Double)] = Array(((a,b),1.0), ((b,a),1.0))

一个不同的函数应该输出 ( ("a" ,"b") , 1.0) 因为 (("b" ,"a") , 1.0) 在数组中

使用 :

1
  Array( ( ("a" ,"b") , 1.0) , (("a" ,"b") , 1.0) ).distinct

返回不同的元素:Array(((a,b),1.0))

是否可以修改 distinct 函数以返回不同的 Tuple 元素而不管它们的顺序如何,或者我是否需要交换元组的位置以使每个元素看起来都是有序的?


基于 LimbSoup\\ 的评论:

如果您愿意使用另一个 case 类代替 Tuple2,您可以使用 equals(Any) 覆盖轻松创建自己的无序元组实现:

1
2
3
4
5
6
7
8
9
10
11
case class UT2[+T1, +T2](_1: T1, _2: T2)  {
  override def hashCode(): Int = _1.hashCode() ^ _2.hashCode()

  override def equals(that: Any): Boolean ={
   that match {
    case UT2(o1, o2) => (_1 == o1 && _2 == o2) || (_1 == o2 && _2 == o1)
    case _ => false
  }}

  lazy val tuple: (T1, T2) = (_1, _2)
}

请注意,您必须覆盖 hashCode(),否则它将无法与 distinct 一起使用,而 distinct 似乎在内部使用了散列集,只是因为您应该这样做。

1
2
val seq = Array((UT2("a","b") , 1.0), (UT2("b","a"), 1.0))
seq.distinct.toList // List((UT2(a,b),1.0))

如果你想在大多数地方在普通元组和无序元组之间自动转换,你可以提供隐式转换:

1
2
3
4
5
6
object UnorderedTupleImplicits {
  implicit def Tuple2UnorderedTuple[T1, T2](t: (T1, T2)): UT2[T1, T2] = UT2(t._1, t._2)
  implicit def UnorderedTuple2Tuple[T1, T2](ut: UT2[T1, T2]): (T1, T2) = ut.tuple
}
import UnorderedTupleImplicits._
val ut: (UT2[String, String], Double) = (("a","b"), 1.0)

确实元组t1:(A,B)不等于t2:(B,A),因为顺序很重要(t1._1 != t2._1)。如果你想要一个不保留顺序的数据结构,因此在与另一个实例进行比较时不使用它,那么使用类似 Set 的东西。只是为了说明这一点:

1
2
3
4
5
scala> (1, 2) == (2, 1)
res0: Boolean = false

scala> Set(1, 2) == Set(2, 1)
res1: Boolean = true

如果您仍然想使用元组,那么您可以编写自己的 distinct 实现。不幸的是,distinct 不是一个高阶函数,它可以使用像 def sorted[B >: A](implicit ord: math.Ordering[B]): List[A].

这样的比较策略


使用 Aleksey Izmailov 回答作为基础:

1
2
3
    val v : Array[((String, String), Double)] = Array( ( ("a" ,"b") , 1.0) , (("b" ,"a") , 1.0) )    
      v.map(m => (Set(m._1._1 , m._1._2) , m._2) ).distinct
 res0: Array[(scala.collection.immutable.Set[String], Double)] = Array((Set(a, b),1.0))