Scala独特的序列

时间:2014-02-12 15:06:11

标签: scala set sequence

在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特性不提供关键的可索引性。

所以问题是:

  1. 这两种实现之间是否有明显的赢家?
  2. 标准集合中还有另一种更好的方法吗?

3 个答案:

答案 0 :(得分:0)

我会创建一个由SeqLike支持的Seq。覆盖添加元素的任何函数,以将元素添加到基础Seq,然后调用distinct以消除重复。

答案 1 :(得分:0)

我更喜欢第二种解决方案,可能会进行修改以在内部维护SetSeq

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)
    }
}