在scala中,是否有可能只有两个元素的Set?

在scala中,是否有可能只有两个元素的Set?

问题描述:

最后,我想有一个案例类交换,以便交换(a,b)==交换(b,a)在scala中,是否有可能只有两个元素的Set?

我想我可以用两个元素的集合,它相当这项工作:

scala> case class Swap(val s:Set[Int]) 
defined class Swap 

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

但这允许任意数量的元素,我想我的元素限制两个 。我发现类Set.Set2,这是一个不变的设置有两个元素的默认实现,但它不工作的它我尝试的方式,或变化:

scala> val a = Set(2, 1) 
a: scala.collection.immutable.Set[Int] = Set(2, 1) 

scala> a.getClass 
res3: Class[_ <: scala.collection.immutable.Set[Int]] = class scala.collection.immutable.Set$Set2 

scala> case class Swap(val s:Set.Set2[Int]) 
defined class Swap 

scala> val swp = Swap(a) 
<console>:10: error: type mismatch; 
found : scala.collection.immutable.Set[Int] 
required: Set.Set2[Int] 
     val swp = Swap(a) 
        ^

所以我的问题是:

  • 有没有办法在我尝试使用Set2?
  • 有没有更好的方法来实现我的案例类Swap?我读过一个人不应该在案例课程中重写equals,尽管这是我的第一个想法。

这是一个通用的实现 -

import scala.collection.immutable.Set.Set2 

def set2[T](a: T, b: T): Set2[T] = Set(a, b).asInstanceOf[Set2[T]] 

case class Swap[T](s: Set2[T]) 

Swap(set2(1,2)) == Swap(set2(2,1)) //true 

您的解决方案没有工作的原因是因为签名的

Set(elems: A*): Set 

在2元的情况下,具体类型将是SET2但编译器不知道,所以你必须将它投到Set2

+1

谢谢,这是我使用的解决方案。为了方便起见,我还添加了第二个构造函数'def this(t1:T,t2:T)= this(Set(t1,t2).asInstanceOf [Set2 [T]])',这允许我用'new Swap (t1,t2)'。 最后我用这种方式匹配模式: 'case Swap(s:Set2 [T])=> { val t1 = s.head val t2 = s.last ...} – 2015-02-06 13:00:58

您可以随时隐藏Swap实施细则,在这种情况下,你居然应该

你可以使用Set执行或者你可以实现它:

// invariant a <= b 
class Swap private (val a: Int, val b: Int) 

object Swap { 
    def apply(a: Int, b: Int): Swap = 
    if (a <= b) new Swap(a, b) else new Swap(b, a) 
} 

不幸的是,你必须在这里使用class并重新实​​现equalshashCode等自己,因为我们无法摆脱的scalac自动生成applyrelated SO Q/A

并使Swap上的所有功能保持不变。

然后等于比较本质上是this.a == other.a && this.b == other.b,我们不需要关心交换了。

+0

我会添加等于的覆盖,以获得@Guillaume期望的结果。另外,定义一个提取器将会非常有用,这种方式在模式匹配上也可以很好地工作。 – Logain 2015-02-06 09:04:29

+0

保持不变并且不允许构造无效对象的要点使得结构相等性能够像我们想要的那样工作。 – phadej 2015-02-06 09:25:47

+0

似乎没有编译:error:构造函数Swap类中的Swap无法在对象Swap中访问。最重要的是,这不再是案例课,因此也没有真正回答这个问题。不过谢谢你! – 2015-02-06 09:52:45

问题是,你不知道静态aSet2 - 就编译器而言,你叫Set(as: A*),并得到某种Set

您可以使用shapeless sized collections来执行一个静态已知的集合大小。

+0

是的,我调用'Set(as:A *)',因为我找不到直接构建'Set2'的方法...... – 2015-02-06 09:56:22

+0

是的,构造函数是'private [collections]'。你可以通过反射来调用它,或者可能更有用的模式匹配:'a match {case s2:Set2 => Swap(s2)}'。但这并不完全安全;如果'a'不是'Set2',它会在运行时抛出一个'MatchError'。 – lmm 2015-02-06 09:58:33