更多集合

最后更新于:2022-04-01 03:05:14

Scala提供了一套很好的集合实现,提供了一些集合类型的抽象。这让你的代码可以与`Foo`的集合交互,而无需担心该集合是是一个`List`,还是`Set`,或是任何你有的类型。 [这里](http://www.decodified.com/scala/collections-api.xml) 提供了一个很好的页面来查看各种集合的默认实现,并链接到他们的scala在线文档。 [TOC=2,2] ## 基础知识 ### 表 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文档](http://www.scala-lang.org/api/current/scala/collection/immutable/List.html) ### 集 Set 集没有重复 ~~~ scala> Set(1, 1, 2) res2: scala.collection.immutable.Set[Int] = Set(1, 2) ~~~ **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/immutable/Set.html) ### 序列 Seq 序列有一个给定的顺序。 ~~~ scala> Seq(1, 1, 2) res3: Seq[Int] = List(1, 1, 2) ~~~ (请注意返回的是一个列表。因为`Seq`是一个特质;而列表是序列的很好实现。如你所见,`Seq`也是一个工厂单例对象,可以用来创建列表。) **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/Seq.html) ### 映射 Map 映射是键值容器。 ~~~ scala> Map('a' -> 1, 'b' -> 2) res4: scala.collection.immutable.Map[Char,Int] = Map((a,1), (b,2)) ~~~ **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html) ## 层次结构 下面介绍的都是特质,它们在可变的(mutable)和不可变的(immutable)的包中都有特定实现。 ### Traversable 所有集合都可以被遍历。这个特质定义了标准函数组合子。 这些组合子根据 `foreach` 来写,所有集合必须实现。 **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/Traversable.html) ### Iterable `iterator()`方法返回一个Iterator来迭代元素。 **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/Iterable.html) ### Seq 序列 有顺序的对象序列。 **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/Seq.html) ### Set 集 没有重复的对象集合。 **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/immutable/Set.html) ### Map 键值对。 **参考** [API文档](http://www.scala-lang.org/api/current/scala/collection/immutable/Map.html) ## 方法 ### Traversable 下面所有方法在子类中都是可用的。参数和返回值的类型可能会因为子类的覆盖而看起来不同。 ~~~ def head : A def tail : Traversable[A] ~~~ 这里是函数组合子定义的地方。 `def map [B] (f: (A) => B) : CC[B]` 返回每个元素都被 `f` 转化的集合 `def foreach[U](f: Elem => U): 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] ~~~ 把映射转换为一个数组,您会得到一个键值对的数组。 ~~~ scala> Map(1 -> 2).toArray res41: Array[(Int, Int)] = Array((1,2)) ~~~ ### Iterable 添加一个迭代器的访问。 ~~~ def iterator: Iterator[A] ~~~ 一个迭代器能给你提供什么? ~~~ def hasNext(): Boolean def next(): A ~~~ 这是非常Java式的。你通常不会看到在Scala中使用迭代器,通常更容易出现的是函数组合器或for循环的使用。 ### Set ~~~ def contains(key: A): Boolean def +(elem: A): Set[A] def -(elem: A): Set[A] ~~~ ### Map 通过键查找的键值对的序列。 可以像这样将一个键值对列表传入apply() ~~~ 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) ~~~ 您也可以使用`++`操作符构建 ~~~ 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 API](http://www.scala-lang.org/api/current/scala/collection/immutable/HashSet.html), [HashMap API](http://www.scala-lang.org/api/current/scala/collection/immutable/HashMap.html) **TreeMap** 是SortedMap的一个子类,它可以让你进行有序访问。 [TreeMap API](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeMap.html) **Vector** 快速随机选择和快速更新。 [Vector API](http://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html) ~~~ scala> IndexedSeq(1, 2, 3) res0: IndexedSeq[Int] = Vector(1, 2, 3) ~~~ **Range** 等间隔的Int有序序列。你经常会在for循环看到。 [Range API](http://www.scala-lang.org/api/current/scala/collection/immutable/Range.html) ~~~ scala> for (i <- 1 to 3) { println(i) } 1 2 3 ~~~ Ranges支持标准的函数组合子。 ~~~ scala> (1 to 3).map { i => i } res0: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) ~~~ ### 默认实现 使用特质的apply方法会给你默认实现的实例,例如,Iterable(1, 2)会返回一个列表作为其默认实现。 ~~~ 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) ~~~ ### 一些描述性的特质 **IndexedSeq** 快速随机访问元素和一个快速的长度操作。"API 文档":http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html **LinearSeq** 通过head快速访问第一个元素,也有一个快速的tail操作。 [API文档](http://www.scala-lang.org/api/current/scala/collection/LinearSeq.html) #### 可变 vs 不可变 不可变 优点 * 在多线程中不会改变 缺点 * 一点也不能改变 Scala允许我们是务实的,它鼓励不变性,但不惩罚我们需要的可变性。这和var vs. val非常相似。我们总是先从val开始并在必要时回退为var。 我们赞成使用不可改变的版本的集合,但如果性能使然,也可以切换到可变的。使用不可变集合意味着你在多线程不会意外地改变事物。 ## 可变集合 前面讨论的所有类都是不可变的。让我们来讨论常用的可变集合。 **HashMap** 定义了 `getOrElseUpdate`, `+=` [HashMap API](http://www.scala-lang.org/api/current/scala/collection/mutable/HashMap.html) ~~~ 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 API](http://www.scala-lang.org/api/current/scala/collection/mutable/ListBuffer.html), [ArrayBuffer API](http://www.scala-lang.org/api/current/scala/collection/mutable/ArrayBuffer.html) **LinkedList and DoubleLinkedList** [LinkedList API](http://www.scala-lang.org/api/current/scala/collection/mutable/LinkedList.html), [DoubleLinkedList API](http://www.scala-lang.org/api/current/scala/collection/mutable/DoubleLinkedList.html) **LinkedList和DoubleLinkedList** [LinkedList API](http://www.scala-lang.org/api/current/scala/collection/mutable/LinkedList.html), [DoubleLinkedList API](http://www.scala-lang.org/api/current/scala/collection/mutable/DoubleLinkedList.html) **PriorityQueue** [API 文档](http://www.scala-lang.org/api/current/scala/collection/mutable/PriorityQueue.html) **Stack 和 ArrayStack** [Stack API](http://www.scala-lang.org/api/current/scala/collection/mutable/Stack.html), [ArrayStack API](http://www.scala-lang.org/api/current/scala/collection/mutable/ArrayStack.html) **StringBuilder** 有趣的是,StringBuilder的是一个集合。 [API文档](http://www.scala-lang.org/api/current/scala/collection/mutable/StringBuilder.html) ## 与Java生活 您可以通过[JavaConverters package](http://www.scala-lang.org/api/current/index.html#scala.collection.JavaConverters$)轻松地在Java和Scala的集合类型之间转换。它用`asScala` 装饰常用的Java集合以和用`asJava` 方法装饰Scala集合。 ~~~ 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 ~~~ Built at [@twitter](http://twitter.com/twitter) by [@stevej](http://twitter.com/stevej), [@marius](http://twitter.com/marius), and [@lahosken](http://twitter.com/lahosken) with much help from [@evanm](http://twitter.com/evanm), [@sprsquish](http://twitter.com/sprsquish), [@kevino](http://twitter.com/kevino), [@zuercher](http://twitter.com/zuercher), [@timtrueman](http://twitter.com/timtrueman), [@wickman](http://twitter.com/wickman), and[@mccv](http://twitter.com/mccv); Russian translation by [appigram](https://github.com/appigram); Chinese simple translation by [jasonqu](https://github.com/jasonqu); Korean translation by [enshahar](https://github.com/enshahar); Licensed under the [Apache License v2.0](http://www.apache.org/licenses/LICENSE-2.0).
';