Scala集合(二)

Scala提供了一系列的集合类的实现。同时,它对于集合类型也进行了一些抽象。这就使得你可以操作一个集合的Foo对象,而不用去关心这个集合是一个ListSet还是其他的什么。

这个网页提供了一个很好的方式来理解scala里的集合的默认实现,并且都链接到了相应的scaladoc。

 

基本集合类

List

标准的linked list。

scala> List(1, 2, 3)
res0: List[Int] = List(1, 2, 3)

你也可以像在函数式语言里一样把它们串接起来。

scala> 1 :: 2 :: 3 :: Nil
res1: List[Int] = List(1, 2, 3)

参考 API文档

 

Set

Set里不包含重复元素

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

参考 API文档

 

Seq

Sequence都有一个预定义的顺序。

scala> Seq(1, 1, 2)
res3: Seq[Int] = List(1, 1, 2)

(注意返回的结果是一个List。Seq是一个trait;List是它的一个实现类。Seq对象是一个工厂对象,正如你所看到的,它会创建一个List。)

参考 API文档

 

Map

Map是保存键-值对的容器。

scala> Map('a' -> 1, 'b' -> 2)
res4: scala.collection.immutable.Map[Char,Int] = Map((a,1), (b,2))

参考 API文档

 

层级关系

上面的这些都是trait,在可变(mutable)包和不可变(immutable)包里都有对应的实现,同时也有其他特殊用途的实现。

 

Traversable

所有的集合都可遍历的。这个trait定义了标准函数组合器。这些组合器都是通过foreach这个方法来实现的,并且所有的集合都实现了这个方法。

参考 API文档

 

Iterable

这个trait有一个iterator()方法,它返回一个可以遍历所有元素的Iterator。 参考 API文档

 

Seq

一组有序的元素。

参考 API文档

 

Set

一组没有重复元素的集合。

参考 API文档

 

Map

键-值对。

参考 API文档

 

方法

Traversable

上面所有的方法在子类中都是可用的。参数和返回值可能会改变,因为子类可以覆盖它们。

def head : A
def tail : Traversable[A]

这里我们可以定义函数组合器。

def map [B] (f: (A) => B) : CC[B]

上面的代码返回一个集合,里面的每一个元素都通过函数f进行了转换。

def foreachU: Unit

对一个集合里的每一个元素都执行函数f

def find (p: (A) => Boolean) : Option[A]

它返回第一个符合断言函数的元素。

def filter (p: (A) => Boolean) : Traversable[A]

这个返回一个包含所有符合断言函数的元素的集合。

切分:

def partition (p: (A) ⇒ Boolean) : (Traversable[A], Traversable[A])

通过一个断言函数把一个集合拆成两份

def groupBy [K] (f: (A) => K) : Map[K, Traversable[A]]

转换:

有趣的是,集合之间可以相互进行转换。

def toArray : Array[A]
def toArray [B >: A] (implicit arg0: ClassManifest[B]) : Array[B]
def toBuffer [B >: A] : Buffer[B]
def toIndexedSeq [B >: A] : IndexedSeq[B]
def toIterable : Iterable[A]
def toIterator : Iterator[A]
def toList : List[A]
def toMap [T, U] (implicit ev: <:<[A, (T, U)]) : Map[T, U]
def toSeq : Seq[A]
def toSet [B >: A] : Set[B]
def toStream : Stream[A]
def toString () : String
def toTraversable : Traversable[A]

我们可以把一个Map转换成一个数组,然后得到一个键值对数组。

scala> Map(1 -> 2).toArray
res41: Array[(Int, Int)] = Array((1,2))

Iterable

这个接口给你提供了一个迭代器iterator。

  def iterator: Iterator[A]

Iterator提供了什么操作呢?

def hasNext(): Boolean
def next(): A

这个是非常‘Java式’的用法。在Scala中,你很少会见到使用iterator的地方,大部分的时候你看到的都是函数组合器以及for循环语句。

 

Set

  def contains(key: A): Boolean
  def +(elem: A): Set[A]
  def -(elem: A): Set[A]

 

Map

一序列键值对,提供按key进行查询的操作。 可以通过给apply()方法传入一个键值对的列表来创建Map:

scala> Map("a" -> 1, "b" -> 2)
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2))

或者按照下面的方式:

scala> Map(("a", 2), ("b", 2))
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,2), (b,2))

题外话

->是什么呢?这是一个特殊的语法,它是一个返回值为元组的方法。

scala> "a" -> 2

res0: (java.lang.String, Int) = (a,2)

记住,它只是下面这种形式的语法糖:

scala> "a".->(2)

res1: (java.lang.String, Int) = (a,2)

你也可以通过++来构造Map

scala> Map.empty ++ List(("a", 1), ("b", 2), ("c", 3))
res0: scala.collection.immutable.Map[java.lang.String,Int] = Map((a,1), (b,2), (c,3))

 

常用的集合子类

HashSet 和 HashMap 支持快速查找的最常用的集合类。HashSet APIHashMap API

TreeMap SortedMap的子类,它提供有序的访问方式。 TreeMap API

Vector 支持快速查找和更新 Vector API

scala> IndexedSeq(1, 2, 3)
res0: IndexedSeq[Int] = Vector(1, 2, 3)

Range 有序的通过空格分隔的Int序列。 在之前很多用来计数的for循环经常使用它。Range API

scala> for (i <- 1 to 3) { println(i) }
1
2
3

Range也支持标准的函数组合器。

scala> (1 to 3).map { i => i }
res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3)

默认实现

在trait上使用apply方法会得到该trait的一个默认实现,例如,Iterable(1,2)返回一个List作为它的默认实现。

scala> Iterable(1, 2)

res0: Iterable[Int] = List(1, 2)

Seq也是这样的,我们之前见过

scala> Seq(1, 2)
res3: Seq[Int] = List(1, 2)

scala> Iterable(1, 2)
res1: Iterable[Int] = List(1, 2)

scala> Sequence(1, 2)
warning: there were deprecation warnings; re-run with -deprecation for details
res2: Seq[Int] = List(1, 2)

Set

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

 

一些描述性的trait

IndexedSeq 支持对元素进行快速随机访问以及快速的length操作 API doc

LinearSeq 只对第一个和最后一个元素支持快速访问。 API doc

 

可变性 vs. 不可变性

不可变性

优点

  • 在多线程场景下不会被改变

缺点

  • 没有办法进行修改

Scala允许我们根据实际需求决定可变性,它鼓励我们只用不可变的对象,但是也不禁止我们使用具有可变性的对象。这个和var与val的场景非常相似。我们一开始都是使用val,当实际需要的时候会改成var。

 

可变集合

我们前面讨论的所有的类都是不可变的。我们现在来讨论一下常用的可变集合。

HashMap 定义了getOrElseUpdate+= HashMap API

scala> val numbers = collection.mutable.Map(1 -> 2)
numbers: scala.collection.mutable.Map[Int,Int] = Map((1,2))

scala> numbers.get(1)
res0: Option[Int] = Some(2)

scala> numbers.getOrElseUpdate(2, 3)
res54: Int = 3

scala> numbers
res55: scala.collection.mutable.Map[Int,Int] = Map((2,3), (1,2))

scala> numbers += (4 -> 1)
res56: numbers.type = Map((2,3), (4,1), (1,2))

 

ListBuffer和ArrayBuffer 定义了+=操作符 ListBuffer APIArrayBuffer API

LinkedList和DoubleLinkedList LinkedList APIDoubleLinkedList API

PriorityQueue API doc

Stack和ArrayStack Stack APIArrayStack API

StringBuilder 有趣的是StringBuilder是竟然一个集合 API doc

 

和Java进行交互

你可以通过 JavaConverters 包在Java和Scala的集合类之间进行转换. 它给常用的Java集合提供了asScala方法,同时给常用的Scala集合提供了asJava方法。

   import scala.collection.JavaConverters._
   val sl = new scala.collection.mutable.ListBuffer[Int]
   val jl : java.util.List[Int] = sl.asJava
   val sl2 : scala.collection.mutable.Buffer[Int] = jl.asScala
   assert(sl eq sl2)

双向转换:

scala.collection.Iterable <=> java.lang.Iterable
scala.collection.Iterable <=> java.util.Collection
scala.collection.Iterator <=> java.util.{ Iterator, Enumeration }
scala.collection.mutable.Buffer <=> java.util.List
scala.collection.mutable.Set <=> java.util.Set
scala.collection.mutable.Map <=> java.util.{ Map, Dictionary }
scala.collection.mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap

 

另外,下面提供了一些单向的转换方法:

scala.collection.Seq => java.util.List
scala.collection.mutable.Seq => java.util.List
scala.collection.Set => java.util.Set
scala.collection.Map => java.util.Map
原文链接: Scala School 翻译: ImportNew.com - 朱伟杰
译文链接: http://www.importnew.com/4543.html
[ 转载请保留原文出处、译者和译文链接。]

关于作者: 朱伟杰

Java开发工程师,业余翻译

查看朱伟杰的更多文章 >>



相关文章

发表评论

Comment form

(*) 表示必填项

还没有评论。

跳到底部
返回顶部