在Scala(2.10)中,我想要一个不可变的SeqLike集合(支持索引),它为用户提供了一个SetLike接口,并且不允许重复元素。理想情况下,这将实现SetLike和SeqLike,但这是不可能的,所以我必须选择一个。我的第一个想法如下:
sealed class IndexableSet[A] ( private val values : Seq[A] )
extends Set[A]
with SetLike[A,IndexableSet[A]]
{
override def empty : IndexableSet[A] = new IndexableSet[A]( Seq[A]() )
def + ( elem : A ) : IndexableSet[A] = values.contains( elem ) match
{
case true => this
case false => new IndexableSet[A]( values :+ elem )
}
def - ( elem : A ) : IndexableSet[A] = values.contains( elem )
{
case true => new IndexableSet[A]( values.filter( _ != elem ) )
case false => this
}
def iterator = values.iterator
def contains( elem : A ) = values.contains( elem )
def apply( index : Int ) = values( index )
def length : Int = values.size
def contents : Seq[A] = values
}
这会暴露一个合适的接口,但不会出现可排序性(没有sortBy或已排序)
因此,我想知道是否将我的实现更改为实现Seq和SeqLike的实现,并伪造Set接口:
sealed class UniqueSeq[A] private ( private val values : IndexedSeq[A] )
extends SeqLike[A,UniqueSeq[A]]
with Seq[A]
with GenericTraversableTemplate[A,UniqueSeq]
{
def apply( idx : Int ) : A = values( idx )
def iterator = values.iterator
def length = values.length
override def companion: GenericCompanion[UniqueSeq] = new GenericCompanion[UniqueSeq]()
{
def newBuilder[A]: Builder[A, UniqueSeq[A]] = new Builder[A, UniqueSeq[A]]
{
val elems = new ArrayBuffer[A]()
def +=(a:A) = { elems += a; this }
def clear() { elems.clear }
def result(): UniqueSeq[A] = new UniqueSeq[A](elems)
}
}
def + ( elem : A ) : UniqueSeq[A] = values.contains( elem ) match
{
case true => this
case false => new UniqueSeq[A]( values :+ elem )
}
def - ( elem : A ) : UniqueSeq[A] = values.contains( elem ) match
{
case true => new UniqueSeq[A]( values.filter( _ != elem ) )
case false => this
}
}
我不确定哪个更好 - 或者是否有另一种方式。我知道有TreeSet
之类的东西,但SortedSet特性不提供关键的可索引性。
所以问题是:
答案 0 :(得分:0)
我会创建一个由SeqLike
支持的Seq
。覆盖添加元素的任何函数,以将元素添加到基础Seq
,然后调用distinct
以消除重复。
答案 1 :(得分:0)
我更喜欢第二种解决方案,可能会进行修改以在内部维护Set
和Seq
:
sealed class UniqueSeq[A] private ( values : IndexedSeq[A], valueSet : Set[A] )
extends SeqLike[A,UniqueSeq[A]]
with Seq[A]
with GenericTraversableTemplate[A,UniqueSeq]
{
def apply( idx : Int ) : A = values( idx )
def iterator = values.iterator
def length = values.length
override def companion: GenericCompanion[UniqueSeq] = new GenericCompanion[UniqueSeq]()
{
def newBuilder[A]: Builder[A, UniqueSeq[A]] = new Builder[A, UniqueSeq[A]]
{
val elems = new ArrayBuffer[A]()
def +=(a:A) = { elems += a; this }
def clear() { elems.clear }
def result(): UniqueSeq[A] = new UniqueSeq[A](elems)
}
}
def + ( elem : A ) : UniqueSeq[A] = valueSet.contains( elem ) match
{
case true => this
case false => new UniqueSeq[A]( values :+ elem, valueSet + elem )
}
def - ( elem : A ) : UniqueSeq[A] = valueSet.contains( elem ) match
{
case true => new UniqueSeq[A]( values.filter( _ != elem ), valueSet - elem )
case false => this
}
}
答案 2 :(得分:0)
以下代码适用于我的应用程序。它将您的代码与此问题的代码混合在一起: Create a custom scala collection where map defaults to returning the custom collection?
class Unique[A] private (list: Vector[A], set: Set[A]) extends Traversable[A]
with TraversableLike[A, Unique[A]]
with GenericTraversableTemplate[A, Unique]
{
def apply(index: Int): A = list(index)
override def companion: GenericCompanion[Unique] = Unique
def foreach[U](f: A => U) { list foreach f }
override def seq = list
def +(elem: A): Unique[A] = {
if (set.contains(elem)) this
else new Unique(list :+ elem, set + elem)
}
def -(elem: A): Unique[A] = {
if (set.contains(elem)) new Unique(list.filter(_ != elem), set - elem)
else this
}
def --(elems: Traversable[A]): Unique[A] = {
val set = elems.toSet
val values2 = list.filterNot(set.contains)
new Unique(values2, values2.toSet)
}
def ++(elems: Traversable[A]): Unique[A] = {
val list2 = elems.filterNot(set.contains)
val values2 = list ++ list2
new Unique(values2, values2.toSet)
}
def contains(elem: A): Boolean = set.contains(elem)
def zipWithIndex: Traversable[(A, Int)] = list.zipWithIndex
}
object Unique extends TraversableFactory[Unique] {
def newBuilder[A] = new UniqueBuilder[A]
implicit def canBuildFrom[A]: CanBuildFrom[Coll, A, Unique[A]] = {
new CanBuildFrom[Coll, A, Unique[A]] {
def apply(): Builder[A, Unique[A]] = new UniqueBuilder()
def apply(from: Coll): Builder[A, Unique[A]] = apply()
}
}
class UniqueBuilder[A] extends Builder[A, Unique[A]] {
private val list = Vector.newBuilder[A]
private val set = new HashSet[A]()
def += (elem: A): this.type = {
if (!set.contains(elem)) {
list += elem
set += elem
}
this
}
def clear() {
list.clear()
set.clear()
}
def result(): Unique[A] = new Unique(list.result, set.toSet)
}
}