2015-02-06 142 views
3

最後,我想有一個案例類交換,以便交換(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,儘管這是我的第一個想法。

回答

3

這是一個通用的實現 -

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

1

您可以隨時隱藏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

1

問題是,你不知道靜態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

相關問題