Key points in this chapter
- All collections are extended from iterable traits
- There are three main classes of collections: sequence, set, map
- Scala provides both mutable and immutable versions for almost all collection classes
- The Scala list is either empty or has a tail, where the trailer itself is a list
- Set is a set of no precedence
- Use Linkedhashset to preserve the insertion order, or use SortedSet to iterate sequentially
- ' + ' adds elements to the unordered set; +: and: + Forward or backward append to sequence; + + adds two sets together;-and – Removes elements
- Iterable and seq traits have dozens of methods for common operations
- Mapping, folding, and zipper operations are useful tips for applying a function or action to an element in a collection
The main collection traits
The key traits in the Scala collection inheritance hierarchy:
The iterable value is the set of iterator that can be used to access all the elements in the collection, similar to the C + + iterator.
val coll = ... //某种Iterableval iter = coll.iteratorwhile (iter.hasNext) { 对iter.next() 执行某种操作}
A seq is a sequence of values that have precedence, such as numbers or lists. INDEXEDSEQ allows us to quickly access elements by using subscripts.
Set is a set of values that have no precedence. In SortedSet, the elements are sorted.
A map is a set (key, value) duality. SortedMap are sorted by key.
Each Scala collection trait or class has a companion object with an apply method that can be used to build an instance of the collection instead of using new, a design called the "Uniform Creation principle".
Mutable and Immutable collections
Scala supports both mutable and immutable collections. Scala takes precedence over immutable collections, so you can safely share their references. Any modification to an immutable collection returns a new immutable collection that shares most of the elements.
def digits(n: Int): Set[Int] = { if0) digits(-n) elseif10) Set(n) else1010)}
This example uses recursion to generate new collections constantly, but pay attention to the depth of recursion.
Sequence
The most important immutable sequence:
Vector is an immutable version of Arraybuffer, which, like the vector of C + +, can be accessed quickly and randomly by subscript. The Scala vector is implemented in the form of a tree structure, where each node can have no more than 32 sub-nodes. This requires only 4 layers of nodes for vectors with 1 million elements.
Range represents an integer sequence, such as 0,1,2,3,4,5 or 10,20,30. The rang object does not store all values but only the start value, end value, and increment value.
Most useful variable sequence:
List
In Scala, the list is either nil (empty list) or a HEAD element plus a tail, and tail is a list. For example:
val digits = List(4,2)digits.head // 4digits.tail // List(2)// 2digits.tail.tail // Nil
:: operator creates a list from the given header and tail:
9 :: List(42) // List(9,4,2)// 等同于942 :: Nil // 这里是又结合的
Traversing linked lists: iterators, recursion, or pattern matching can be used
def sum(lst: List[Int]): Int = { if0else lst.head + sum(lst.tail)}defmatch { case0 case h :: t => h + sum(t)}
Variable list
The variable linkedlist can either modify the header (assign a value to the Elem reference) or modify the tail (assigning a value to the next reference):
val lst = scala.collection.mutable.LinkedList(1, -27, -9)// 修改值var cur = lstwhile (cur != Nil) { if00 cur = cur.next}// 去除每两个中的一个var cur = lstwhile (cur != Nil && cur.next != Nil) { cur.next = cur.next.next cur = cur.next}
Note: If you want to turn a node in the list into the last node of the list, you cannot set the next reference to nil, and the next reference should be set to Linkedlist.empty. Do not set to NULL, or you will encounter a null pointer error while traversing the list.
Set
A set is a collection of elements that are not duplicated, the same as set in C + +. Sets do not preserve the order in which elements are inserted, by default the set is implemented as a hash set.
A chained hash set remembers the order in which elements are inserted, and it maintains a linked list to achieve this purpose.
val weekdays = scala.collection.mutable.LinkedHashSet("Mo""Tu""We""Th""Fr")
For SortedSet, sorted sets are implemented using a red-black tree. Scala does not have a mutable sorted set, as has been said before.
Some common operations of the set:
Valdigits = Set (1,7,2,9) digits contains0 //FalseSet (1,2) Subsetof digits//TrueValPrimes = Set (2,3,5,7) Digits Union primes//Set (1,2,3,5,7,9)//equal todigits | Primes//or digits + + primesDigits intersect primes//Set (2, 7)//equal toDigits & primesdigits diff primes//Set (1, 9)//equal toDigits--primes
operator for adding or removing elements
In general, + is used to add elements to an order-free collection, and +: and: + is to add elements to the beginning or end of a set that has precedence.
Vector(1,2,35 // Vector(1,2,3,5)1 +: Vector(1,2,3) // Vector(1,1,2,3)
Common methods
The most important way to iterable traits:
The SEQ traits are added on the basis of iterable traits:
To map a function to a collection
The map method can apply a function to each element of a collection and produce a collection of its results. For example:
val names = List("Peter""Paul""Mary")names.map(_.toUpperCase) // List("PETER", "PAUL", "MARY")// 等同于foryield n.toUpperCase
If the function produces a set rather than a single value, use Flatmap to string all the values together. For example:
def// List(Vector("PETER", "peter"), Vector("PAUL", "paul"), Vector("MARY", "mary"))names.flatmap(ulcase) // List("PETER", "peter", "PAUL", "paul", "MARY", "mary")
The Collect method is used for partial functions-and there are no functions defined for all possible input values. For example:
" -3+4". collect { Case ' + '=1; Case '-'=-1}//Vector ( -1,1)" -3+4". collect { Case '-'=-1}//Vector ( -1)" -3+4". collect { Case ' + '=1}//Vector (1)" -3+4". collect { Case ' * '=1}//Vector ()
The Foreach method applies a function to individual elements but does not care about the return value of the function.
names.foreach(println)
Simplification, folding and scanning
The Reduceleft, Reduceright, Foldleft, Foldright, Scanleft, and Scanright methods will combine the elements in the collection with a two-tuple function:
List (1,7,2,9). Reduceleft (_-_)//((1-7)-2)-9List (1,7,2,9). Reduceright (_-_)//1-(7-(2-9))List (1,7,2,9). Foldleft (0)(_ - _)//0-1 -7-2-9List (1,7,2,9). Foldright (0)(_ - _)//1-(7-(2-(9-0)))(1ToTen). Scanleft (0)(_ + _)//Vector (0, 1, 3, 6, ten, a.,
Zipper operation
The previous section has already covered the zipper operation. In addition to the Zip method, there are Zipall and Zipwithindex methods
List(5.020,09.73.14.3).zipAll(List(1020.01) // List((5.0, 10), (20.0, 2), (9.7, 1), (3.1, 1), (4.3, 1))"Scala".zipWithIndex // Vector((‘S‘, 0), (‘c‘, 1), (‘a‘, 2), (‘l‘, 3), (‘a‘, 4) )
Iterators
The advantage of iterators is that you don't have to read all the expensive collections into memory. For example, to read a file operation, Source.fromfile outputs an iterator that uses the Hasnext and next methods to traverse:
while (iter.hasNext) 对 iter.next() 执行某种操作
Notice where the iterator is pointing more. After you call a method such as map, filter, count, sum, length, and so on, the iterator will be at the end of the collection, and you can no longer use it. For other methods, such as find or take, the iterator is located after the element has been found or has been acquired.
Flow
A stream is an immutable list of trailing lazy computations-that is, it is calculated only when you need it.
def1)val tenOrMore = numsFrom(10) // 得到一个 Stream(10, ?) 流对象,尾部未被求值temOrMore.tail.tail.tail // Stream(13, ?)
The method of streaming is lazy execution. For example:
val squares = numsFrom(1).map(x => x * x) // 产出 Stream(1, ?)// 需要调用squares.tail来强制对下一个元素求值squares.tail // Stream(4, ?)// 使用take和force强制求指定数量的值squares.take(5).force // Stream(1,4,9,16,25)
Note: do not use Squares.force directly, which will be evaluated for all members of an infinite stream, throwing outofmemoryerror.
Lazy View
Applying the View method can also implement lazy execution, which produces a collection whose methods are always lazy to execute. For example:
val powers = (01000).view.map(pow(10, _))powers(100) //pow(10, 100)被计算,其他值的幂没有被计算
Unlike a stream, view even the first element is not evaluated unless you are actively calculating it. View does not cache any values, and each call is recalculated.
Lazy collections are good for dealing with large collections that are transformed in many ways, because it avoids the need to build large intermediate collections. For example:
(01000).map(pow(10, _)).map(1 / _) // 1(01000).view.map(pow(10, _)).map(1 / _).force // 2
The first formula produces two sets, each element of the first set is POW (ten, N), and the second set is the inverse of the elements in each set in the first collection. While the second expression uses view views, when the action is enforced, the two actions are executed at the same time for each element, and no additional intermediate collections need to be built.
Interop with a Java collection
Thread-Safe collections
The Scala class library provides six qualities that you can mix into a collection to synchronize the operations of the collection:
Synchronizedbuffer
Synchronizedmap
Synchronizedpriorityqueue
Synchronizedqueue
Synchronizedset
Synchronizedstack
For example:
valnewwith scala.collection.mutable.SynchronizedMap[String, Int]
Of course, there are more efficient collections, such as Concurrenthashmap or CONCURRENTSKIPLISTMAP, that are more efficient than simply performing all the methods synchronously.
Parallel collections
The par method of the collection outputs a parallel implementation of the current collection, such as Sum sum, where multiple threads can compute the sums of different chunks concurrently, and in the last part the results are aggregated together.
coll.par.sum
You can apply par parallel for loop to the collection you want to traverse
for(i <- (0100" ")
In the For/yield cycle, the results are assembled in turn:
for(i <- (0100yield" "
Note Here whether the variable is a shared variable or a local variable within the loop:
var0for (c <- coll.par) {if201} // error
* * Note: The type of parallel collection returned by the **par method is a type that extends from Parseq, Parset, or parmap traits, all of which are subtypes of pariterable. These are not iterable subtypes, so you cannot pass parallel collections to the expected iterable, Seq, Set, map methods. You can use the Ser method to convert a parallel collection back to a serial collection, or you can implement methods that accept generic geniterable, Genseq, Genseq, and Genmap types of parameters.
Description: Not all methods can be parallelized. For example, Reduceleft, Reduceright requires each operator to be applied sequentially in succession.
Learn the Scala Chapter 13th----Collection