From 18cce7299c8304632ea3d63c1e7414e958ae3bea Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Thu, 29 Sep 2022 17:25:35 +0200 Subject: [PATCH 1/5] Add code tabs for collections-2.13/sets --- _overviews/collections-2.13/sets.md | 120 +++++++++++++++++++--------- 1 file changed, 82 insertions(+), 38 deletions(-) diff --git a/_overviews/collections-2.13/sets.md b/_overviews/collections-2.13/sets.md index 835c4a45eb..40b4cc8d46 100644 --- a/_overviews/collections-2.13/sets.md +++ b/_overviews/collections-2.13/sets.md @@ -18,14 +18,18 @@ permalink: /overviews/collections-2.13/:title.html For example: - - scala> val fruit = Set("apple", "orange", "peach", "banana") - fruit: scala.collection.immutable.Set[java.lang.String] = Set(apple, orange, peach, banana) - scala> fruit("peach") - res0: Boolean = true - scala> fruit("potato") - res1: Boolean = false - +{% tabs sets_1 %} +{% tab 'Scala 2 and 3' for=sets_1 %} +``` +scala> val fruit = Set("apple", "orange", "peach", "banana") +fruit: scala.collection.immutable.Set[java.lang.String] = Set(apple, orange, peach, banana) +scala> fruit("peach") +res0: Boolean = true +scala> fruit("potato") +res1: Boolean = false +``` +{% endtab %} +{% endtabs %} * **Additions** `incl` and `concat` (or `+` and `++`, respectively), which add one or more elements to a set, yielding a new set. * **Removals** `excl` and `removedAll` (or `-` and `--`, respectively), which remove one or more elements from a set, yielding a new set. @@ -85,22 +89,33 @@ The operation `s += elem` adds `elem` to the set `s` as a side effect, and retur The choice of the method names `+=` and `-=` means that very similar code can work with either mutable or immutable sets. Consider first the following REPL dialogue which uses an immutable set `s`: - scala> var s = Set(1, 2, 3) - s: scala.collection.immutable.Set[Int] = Set(1, 2, 3) - scala> s += 4 - scala> s -= 2 - scala> s - res2: scala.collection.immutable.Set[Int] = Set(1, 3, 4) +{% tabs sets_2 %} +{% tab 'Scala 2 and 3' for=sets_2 %} +``` +scala> var s = Set(1, 2, 3) +s: scala.collection.immutable.Set[Int] = Set(1, 2, 3) +scala> s += 4 +scala> s -= 2 +scala> s +res2: scala.collection.immutable.Set[Int] = Set(1, 3, 4) +``` +{% endtab %} +{% endtabs %} We used `+=` and `-=` on a `var` of type `immutable.Set`. A statement such as `s += 4` is an abbreviation for `s = s + 4`. So this invokes the addition method `+` on the set `s` and then assigns the result back to the `s` variable. Consider now an analogous interaction with a mutable set. - - scala> val s = collection.mutable.Set(1, 2, 3) - s: scala.collection.mutable.Set[Int] = Set(1, 2, 3) - scala> s += 4 - res3: s.type = Set(1, 4, 2, 3) - scala> s -= 2 - res4: s.type = Set(1, 4, 3) +{% tabs sets_3 %} +{% tab 'Scala 2 and 3' for=sets_3 %} +``` +scala> val s = collection.mutable.Set(1, 2, 3) +s: scala.collection.mutable.Set[Int] = Set(1, 2, 3) +scala> s += 4 +res3: s.type = Set(1, 4, 2, 3) +scala> s -= 2 +res4: s.type = Set(1, 4, 3) +``` +{% endtab %} +{% endtabs %} The end effect is very similar to the previous interaction; we start with a `Set(1, 2, 3)` and end up with a `Set(1, 3, 4)`. However, even though the statements look the same as before, they do something different. `s += 4` now invokes the `+=` method on the mutable set value `s`, changing the set in place. Likewise, `s -= 2` now invokes the `-=` method on the same set. @@ -120,34 +135,63 @@ A [SortedSet](https://www.scala-lang.org/api/current/scala/collection/SortedSet. To create an empty [TreeSet](https://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html), you could first specify the desired ordering: - scala> val myOrdering = Ordering.fromLessThan[String](_ > _) - myOrdering: scala.math.Ordering[String] = ... +{% tabs sorted-sets_1 %} +{% tab 'Scala 2 and 3' for=sorted-sets_1 %} +``` +scala> val myOrdering = Ordering.fromLessThan[String](_ > _) +myOrdering: scala.math.Ordering[String] = ... +``` +{% endtab %} +{% endtabs %} Then, to create an empty tree set with that ordering, use: - scala> TreeSet.empty(myOrdering) - res1: scala.collection.immutable.TreeSet[String] = TreeSet() - -Or you can leave out the ordering argument but give an element type or the empty set. In that case, the default ordering on the element type will be used. - - scala> TreeSet.empty[String] - res2: scala.collection.immutable.TreeSet[String] = TreeSet() +{% tabs sorted-sets_2 %} +{% tab 'Scala 2 and 3' for=sorted-sets_2 %} +``` +scala> TreeSet.empty(myOrdering) +res1: scala.collection.immutable.TreeSet[String] = TreeSet() +``` +{% endtab %} +{% endtabs %} + +Or you can leave out the ordering argument but give an element type for the empty set. In that case, the default ordering on the element type will be used. + +{% tabs sorted-sets_3 %} +{% tab 'Scala 2 and 3' for=sorted-sets_3 %} +``` +scala> TreeSet.empty[String] +res2: scala.collection.immutable.TreeSet[String] = TreeSet() +``` +{% endtab %} +{% endtabs %} If you create new sets from a tree-set (for instance by concatenation or filtering) they will keep the same ordering as the original set. For instance, - scala> res2 + "one" + "two" + "three" + "four" - res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two) +{% tabs sorted-sets_4 %} +{% tab 'Scala 2 and 3' for=sorted-sets_4 %} +``` +scala> res2 + "one" + "two" + "three" + "four" +res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two) +``` +{% endtab %} +{% endtabs %} Sorted sets also support ranges of elements. For instance, the `range` method returns all elements from a starting element up to, but excluding, an end element. Or, the `from` method returns all elements greater or equal than a starting element in the set's ordering. The result of calls to both methods is again a sorted set. Examples: - scala> res3.range("one", "two") - res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three) - scala> res3 rangeFrom "three" - res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two) - +{% tabs sorted-sets_5 %} +{% tab 'Scala 2 and 3' for=sorted-sets_5 %} +``` +scala> res3.range("one", "two") +res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three) +scala> res3 rangeFrom "three" +res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two) +``` +{% endtab %} +{% endtabs %} ### Bitsets ### -Bitsets are sets of non-negative integer elements that are implemented in one or more words of packed bits. The internal representation of a [BitSet](https://www.scala-lang.org/api/current/scala/collection/BitSet.html) uses an array of `Long`s. The first `Long` covers elements from 0 to 63, the second from 64 to 127, and so on (Immutable bitsets of elements in the range of 0 to 127 optimize the array away and store the bits directly in a one or two `Long` fields.) For every `Long`, each of its 64 bits is set to 1 if the corresponding element is contained in the set, and is unset otherwise. It follows that the size of a bitset depends on the largest integer that's stored in it. If `N` is that largest integer, then the size of the set is `N/64` `Long` words, or `N/8` bytes, plus a small number of extra bytes for status information. +Bitsets are sets of non-negative integer elements that are implemented in one or more words of packed bits. The internal representation of a [BitSet](https://www.scala-lang.org/api/current/scala/collection/BitSet.html) uses an array of `Long`s. The first `Long` covers elements from 0 to 63, the second from 64 to 127, and so on (Immutable bitsets of elements in the range of 0 to 127 optimize the array away and store the bits directly in a one or two `Long` fields). For every `Long`, each of its 64 bits is set to 1 if the corresponding element is contained in the set, and is unset otherwise. It follows that the size of a bitset depends on the largest integer that's stored in it. If `N` is that largest integer, then the size of the set is `N/64` `Long` words, or `N/8` bytes, plus a small number of extra bytes for status information. Bitsets are hence more compact than other sets if they contain many small elements. Another advantage of bitsets is that operations such as membership test with `contains`, or element addition and removal with `+=` and `-=` are all extremely efficient. From 563ca41ab29a7216de23c7f57191f34647ea340b Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Thu, 29 Sep 2022 17:39:52 +0200 Subject: [PATCH 2/5] Small corrections proposed to collections-2.13/maps: remove '"' that look like unnecessary. --- _overviews/collections-2.13/maps.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/_overviews/collections-2.13/maps.md b/_overviews/collections-2.13/maps.md index 3b512ce5db..a8fb77971e 100644 --- a/_overviews/collections-2.13/maps.md +++ b/_overviews/collections-2.13/maps.md @@ -16,7 +16,7 @@ A [Map](https://www.scala-lang.org/api/current/scala/collection/Map.html) is an The fundamental operations on maps are similar to those on sets. They are summarized in the following table and fall into the following categories: -* **Lookup** operations `apply`, `get`, `getOrElse`, `contains`, and `isDefinedAt`. These turn maps into partial functions from keys to values. The fundamental lookup method for a map is: `def get(key): Option[Value]`. The operation "`m get key`" tests whether the map contains an association for the given `key`. If so, it returns the associated value in a `Some`. If no key is defined in the map, `get` returns `None`. Maps also define an `apply` method that returns the value associated with a given key directly, without wrapping it in an `Option`. If the key is not defined in the map, an exception is raised. +* **Lookup** operations `apply`, `get`, `getOrElse`, `contains`, and `isDefinedAt`. These turn maps into partial functions from keys to values. The fundamental lookup method for a map is: `def get(key): Option[Value]`. The operation `m get key` tests whether the map contains an association for the given `key`. If so, it returns the associated value in a `Some`. If no key is defined in the map, `get` returns `None`. Maps also define an `apply` method that returns the value associated with a given key directly, without wrapping it in an `Option`. If the key is not defined in the map, an exception is raised. * **Additions and updates** `+`, `++`, `updated`, which let you add new bindings to a map or change existing bindings. * **Removals** `-`, `--`, which remove bindings from a map. * **Subcollection producers** `keys`, `keySet`, `keysIterator`, `values`, `valuesIterator`, which return a map's keys and values separately in various forms. @@ -78,7 +78,7 @@ Mutable maps support in addition the operations summarized in the following tabl | **Cloning:** | | | `ms.clone` |Returns a new mutable map with the same mappings as `ms`.| -The addition and removal operations for maps mirror those for sets. A mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There is also the variant `m.put(key, value)`, which returns an `Option` value that contains the value previously associated with `key`, or `None` if the `key` did not exist in the map before. +The addition and removal operations for maps mirror those for sets. A mutable map `m` is usually updated in place, using the two variants `m(key) = value` or `m += (key -> value)`. There is also the variant `m.put(key, value)`, which returns an `Option` value that contains the value previously associated with `key`, or `None` if the `key` did not exist in the map before. The `getOrElseUpdate` is useful for accessing maps that act as caches. Say you have an expensive computation triggered by invoking a function `f`: @@ -129,7 +129,7 @@ You can now create a more efficient caching version of the `f` function: {% endtab %} {% endtabs %} -Note that the second argument to `getOrElseUpdate` is "by-name", so the computation of `f("abc")` above is only performed if `getOrElseUpdate` requires the value of its second argument, which is precisely if its first argument is not found in the `cache` map. You could also have implemented `cachedF` directly, using just basic map operations, but it would take more code to do so: +Note that the second argument to `getOrElseUpdate` is by-name, so the computation of `f("abc")` above is only performed if `getOrElseUpdate` requires the value of its second argument, which is precisely if its first argument is not found in the `cache` map. You could also have implemented `cachedF` directly, using just basic map operations, but it would take more code to do so: {% tabs cacheF class=tabs-scala-version %} From 7aca6bfd49074f664775f213db85a5bc1a6a7882 Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Sat, 1 Oct 2022 16:40:25 +0200 Subject: [PATCH 3/5] Add code tabs for collections-2.13/concrete-immutable-collection-classes --- .../concrete-immutable-collection-classes.md | 100 +++++++++++++++++- 1 file changed, 97 insertions(+), 3 deletions(-) diff --git a/_overviews/collections-2.13/concrete-immutable-collection-classes.md b/_overviews/collections-2.13/concrete-immutable-collection-classes.md index 24f1b70648..5964346cf3 100644 --- a/_overviews/collections-2.13/concrete-immutable-collection-classes.md +++ b/_overviews/collections-2.13/concrete-immutable-collection-classes.md @@ -24,25 +24,42 @@ A [LazyList](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/colle Whereas lists are constructed with the `::` operator, lazy lists are constructed with the similar-looking `#::`. Here is a simple example of a lazy list containing the integers 1, 2, and 3: +{% tabs LazyList_1 %} +{% tab 'Scala 2 and 3' for=LazyList_1 %} +~~~ scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty lazyList: scala.collection.immutable.LazyList[Int] = LazyList() +~~~ +{% endtab %} +{% endtabs %} The head of this lazy list is 1, and the tail of it has 2 and 3. None of the elements are printed here, though, because the list hasn’t been computed yet! Lazy lists are specified to compute lazily, and the `toString` method of a lazy list is careful not to force any extra evaluation. Below is a more complex example. It computes a lazy list that contains a Fibonacci sequence starting with the given two numbers. A Fibonacci sequence is one where each element is the sum of the previous two elements in the series. - +{% tabs LazyList_2 %} +{% tab 'Scala 2 and 3' for=LazyList_2 %} +~~~ scala> def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b) fibFrom: (a: Int,b: Int)LazyList[Int] +~~~ +{% endtab %} +{% endtabs %} This function is deceptively simple. The first element of the sequence is clearly `a`, and the rest of the sequence is the Fibonacci sequence starting with `b` followed by `a + b`. The tricky part is computing this sequence without causing an infinite recursion. If the function used `::` instead of `#::`, then every call to the function would result in another call, thus causing an infinite recursion. Since it uses `#::`, though, the right-hand side is not evaluated until it is requested. Here are the first few elements of the Fibonacci sequence starting with two ones: +{% tabs LazyList_3 %} +{% tab 'Scala 2 and 3' for=LazyList_3 %} +~~~ scala> val fibs = fibFrom(1, 1).take(7) fibs: scala.collection.immutable.LazyList[Int] = LazyList() scala> fibs.toList res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13) +~~~ +{% endtab %} +{% endtabs %} ## Immutable ArraySeqs @@ -56,6 +73,8 @@ and thus they can be much more convenient to write. ArraySeqs are built and updated just like any other sequence. +{% tabs ArraySeq_1 %} +{% tab 'Scala 2 and 3' for=ArraySeq_1 %} ~~~ scala> val arr = scala.collection.immutable.ArraySeq(1, 2, 3) arr: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3) @@ -64,16 +83,22 @@ arr2: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3, 4) scala> arr2(0) res22: Int = 1 ~~~ +{% endtab %} +{% endtabs %} ArraySeqs are immutable, so you cannot change an element in place. However, the `updated`, `appended` and `prepended` operations create new ArraySeqs that differ from a given ArraySeq only in a single element: +{% tabs ArraySeq_2 %} +{% tab 'Scala 2 and 3' for=ArraySeq_2 %} ~~~ scala> arr.updated(2, 4) res26: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 4) scala> arr res27: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3) ~~~ +{% endtab %} +{% endtabs %} As the last line above shows, a call to `updated` has no effect on the original ArraySeq `arr`. @@ -91,6 +116,9 @@ but linear for `ArraySeq`, and, conversely, indexed access is constant for `Arra Vectors are built and modified just like any other sequence. +{% tabs Vector_1 %} +{% tab 'Scala 2 and 3' for=Vector_1 %} +~~~ scala> val vec = scala.collection.immutable.Vector.empty vec: scala.collection.immutable.Vector[Nothing] = Vector() scala> val vec2 = vec :+ 1 :+ 2 @@ -99,8 +127,11 @@ Vectors are built and modified just like any other sequence. vec3: scala.collection.immutable.Vector[Int] = Vector(100, 1, 2) scala> vec3(0) res1: Int = 100 +~~~ +{% endtab %} +{% endtabs %} -Vectors are represented as trees with a high branching factor. (The branching factor of a tree or a graph is the number of children at each node.) The details of how this is accomplished [changed](https://github.com/scala/scala/pull/8534) in Scala 2.13.2, but the basic idea remains the same, as follows. +Vectors are represented as trees with a high branching factor (The branching factor of a tree or a graph is the number of children at each node). The details of how this is accomplished [changed](https://github.com/scala/scala/pull/8534) in Scala 2.13.2, but the basic idea remains the same, as follows. Every tree node contains up to 32 elements of the vector or contains up to 32 other tree nodes. Vectors with up to 32 elements can be represented in a single node. Vectors with up to `32 * 32 = 1024` elements can be represented with a single indirection. Two hops from the root of the tree to the final element node are sufficient for vectors with up to 215 elements, three hops for vectors with 220, four hops for vectors with 225 elements and five hops for vectors with up to 230 elements. So for all vectors of reasonable size, an element selection involves up to 5 primitive array selections. This is what we meant when we wrote that element access is "effectively constant time". @@ -108,8 +139,14 @@ Like selection, functional vector updates are also "effectively constant time". Because vectors strike a good balance between fast random selections and fast random functional updates, they are currently the default implementation of immutable indexed sequences: +{% tabs Vector_2 %} +{% tab 'Scala 2 and 3' for=Vector_2 %} +~~~ scala> collection.immutable.IndexedSeq(1, 2, 3) res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) +~~~ +{% endtab %} +{% endtabs %} ## Immutable Queues @@ -117,25 +154,49 @@ A [Queue](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collecti Here's how you can create an empty immutable queue: +{% tabs Queue_1 %} +{% tab 'Scala 2 and 3' for=Queue_1 %} +~~~ scala> val empty = scala.collection.immutable.Queue[Int]() empty: scala.collection.immutable.Queue[Int] = Queue() +~~~ +{% endtab %} +{% endtabs %} You can append an element to an immutable queue with `enqueue`: +{% tabs Queue_2 %} +{% tab 'Scala 2 and 3' for=Queue_2 %} +~~~ scala> val has1 = empty.enqueue(1) has1: scala.collection.immutable.Queue[Int] = Queue(1) +~~~ +{% endtab %} +{% endtabs %} To append multiple elements to a queue, call `enqueueAll` with a collection as its argument: +{% tabs Queue_3 %} +{% tab 'Scala 2 and 3' for=Queue_3 %} +~~~ scala> val has123 = has1.enqueueAll(List(2, 3)) has123: scala.collection.immutable.Queue[Int] = Queue(1, 2, 3) +~~~ +{% endtab %} +{% endtabs %} To remove an element from the head of the queue, you use `dequeue`: +{% tabs Queue_4 %} +{% tab 'Scala 2 and 3' for=Queue_4 %} +~~~ scala> val (element, has23) = has123.dequeue element: Int = 1 has23: scala.collection.immutable.Queue[Int] = Queue(2, 3) +~~~ +{% endtab %} +{% endtabs %} Note that `dequeue` returns a pair consisting of the element removed and the rest of the queue. @@ -143,15 +204,27 @@ Note that `dequeue` returns a pair consisting of the element removed and the res A [Range](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Range.html) is an ordered sequence of integers that are equally spaced apart. For example, "1, 2, 3," is a range, as is "5, 8, 11, 14." To create a range in Scala, use the predefined methods `to` and `by`. +{% tabs Range_1 %} +{% tab 'Scala 2 and 3' for=Range_1 %} +~~~ scala> 1 to 3 res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3) scala> 5 to 14 by 3 res3: scala.collection.immutable.Range = Range(5, 8, 11, 14) +~~~ +{% endtab %} +{% endtabs %} If you want to create a range that is exclusive of its upper limit, then use the convenience method `until` instead of `to`: +{% tabs Range_2 %} +{% tab 'Scala 2 and 3' for=Range_2 %} +~~~ scala> 1 until 3 res2: scala.collection.immutable.Range = Range(1, 2) +~~~ +{% endtab %} +{% endtabs %} Ranges are represented in constant space, because they can be defined by just three numbers: their start, their end, and the stepping value. Because of this representation, most operations on ranges are extremely fast. @@ -167,11 +240,16 @@ Red-black trees are a form of balanced binary tree where some nodes are designat Scala provides implementations of immutable sets and maps that use a red-black tree internally. Access them under the names [TreeSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeSet.html) and [TreeMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeMap.html). - +{% tabs Red-Black_1 %} +{% tab 'Scala 2 and 3' for=Red-Black_1 %} +~~~ scala> scala.collection.immutable.TreeSet.empty[Int] res11: scala.collection.immutable.TreeSet[Int] = TreeSet() scala> res11 + 1 + 3 + 3 res12: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 3) +~~~ +{% endtab %} +{% endtabs %} Red-black trees are the standard implementation of `SortedSet` in Scala, because they provide an efficient iterator that returns all elements in sorted order. @@ -183,6 +261,9 @@ Internally, bit sets use an array of 64-bit `Long`s. The first `Long` in the arr Operations on bit sets are very fast. Testing for inclusion takes constant time. Adding an item to the set takes time proportional to the number of `Long`s in the bit set's array, which is typically a small number. Here are some simple examples of the use of a bit set: +{% tabs BitSet_1 %} +{% tab 'Scala 2 and 3' for=BitSet_1 %} +~~~ scala> val bits = scala.collection.immutable.BitSet.empty bits: scala.collection.immutable.BitSet = BitSet() scala> val moreBits = bits + 3 + 4 + 4 @@ -191,6 +272,9 @@ Operations on bit sets are very fast. Testing for inclusion takes constant time. res26: Boolean = true scala> moreBits(0) res27: Boolean = false +~~~ +{% endtab %} +{% endtabs %} ## VectorMaps @@ -198,6 +282,8 @@ A [VectorMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/coll a map using both a `Vector` of keys and a `HashMap`. It provides an iterator that returns all the entries in their insertion order. +{% tabs VectorMap_1 %} +{% tab 'Scala 2 and 3' for=VectorMap_1 %} ~~~ scala> val vm = scala.collection.immutable.VectorMap.empty[Int, String] vm: scala.collection.immutable.VectorMap[Int,String] = @@ -211,6 +297,8 @@ vm2: scala.collection.immutable.VectorMap[Int,String] = scala> vm2 == Map(2 -> "two", 1 -> "one") res29: Boolean = true ~~~ +{% endtab %} +{% endtabs %} The first lines show that the content of the `VectorMap` keeps the insertion order, and the last line shows that `VectorMap`s are comparable with other `Map`s and that this comparison does not take the @@ -220,8 +308,14 @@ order of elements into account. A [ListMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/ListMap.html) represents a map as a linked list of key-value pairs. In general, operations on a list map might have to iterate through the entire list. Thus, operations on a list map take time linear in the size of the map. In fact there is little usage for list maps in Scala because standard immutable maps are almost always faster. The only possible exception to this is if the map is for some reason constructed in such a way that the first elements in the list are selected much more often than the other elements. +{% tabs ListMap_1 %} +{% tab 'Scala 2 and 3' for=ListMap_1 %} +~~~ scala> val map = scala.collection.immutable.ListMap(1->"one", 2->"two") map: scala.collection.immutable.ListMap[Int,java.lang.String] = Map(1 -> one, 2 -> two) scala> map(2) res30: String = "two" +~~~ +{% endtab %} +{% endtabs %} From cd8f2d164fbe289658ef70d3056921d3a5141f89 Mon Sep 17 00:00:00 2001 From: Luc Henninger Date: Sat, 1 Oct 2022 17:07:35 +0200 Subject: [PATCH 4/5] Add code tabs for collections-2.13/concrete-mutable-collection-classes --- .../concrete-mutable-collection-classes.md | 94 ++++++++++++++++++- 1 file changed, 93 insertions(+), 1 deletion(-) diff --git a/_overviews/collections-2.13/concrete-mutable-collection-classes.md b/_overviews/collections-2.13/concrete-mutable-collection-classes.md index e0d9c5fb19..e8acb12a6e 100644 --- a/_overviews/collections-2.13/concrete-mutable-collection-classes.md +++ b/_overviews/collections-2.13/concrete-mutable-collection-classes.md @@ -18,6 +18,9 @@ You've now seen the most commonly used immutable collection classes that Scala p An [ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayBuffer.html) buffer holds an array and a size. Most operations on an array buffer have the same speed as for an array, because the operations simply access and modify the underlying array. Additionally, array buffers can have data efficiently added to the end. Appending an item to an array buffer takes amortized constant time. Thus, array buffers are useful for efficiently building up a large collection whenever the new items are always added to the end. +{% tabs ArrayBuffer_1 %} +{% tab 'Scala 2 and 3' for=ArrayBuffer_1 %} +~~~ scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int] buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() scala> buf += 1 @@ -26,24 +29,36 @@ An [ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/c res33: buf.type = ArrayBuffer(1, 10) scala> buf.toArray res34: Array[Int] = Array(1, 10) +~~~ +{% endtab %} +{% endtabs %} ## List Buffers A [ListBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ListBuffer.html) is like an array buffer except that it uses a linked list internally instead of an array. If you plan to convert the buffer to a list once it is built up, use a list buffer instead of an array buffer. +{% tabs ListBuffer_1 %} +{% tab 'Scala 2 and 3' for=ListBuffer_1 %} +~~~ scala> val buf = scala.collection.mutable.ListBuffer.empty[Int] buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer() scala> buf += 1 res35: buf.type = ListBuffer(1) scala> buf += 10 res36: buf.type = ListBuffer(1, 10) - scala> buf.toList + scala> buf.to(List) res37: List[Int] = List(1, 10) +~~~ +{% endtab %} +{% endtabs %} ## StringBuilders Just like an array buffer is useful for building arrays, and a list buffer is useful for building lists, a [StringBuilder](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/StringBuilder.html) is useful for building strings. String builders are so commonly used that they are already imported into the default namespace. Create them with a simple `new StringBuilder`, like this: +{% tabs StringBuilders_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=StringBuilders_1 %} +~~~ scala> val buf = new StringBuilder buf: StringBuilder = scala> buf += 'a' @@ -52,6 +67,21 @@ Just like an array buffer is useful for building arrays, and a list buffer is us res39: buf.type = abcdef scala> buf.toString res41: String = abcdef +~~~ +{% endtab %} +{% tab 'Scala 3' for=StringBuilders_1 %} +~~~ + scala> val buf = StringBuilder() + buf: StringBuilder = + scala> buf += 'a' + res38: buf.type = a + scala> buf ++= "bcdef" + res39: buf.type = abcdef + scala> buf.toString + res41: String = abcdef +~~~ +{% endtab %} +{% endtabs %} ## ArrayDeque @@ -66,6 +96,9 @@ an `ArrayBuffer`. Scala provides mutable queues in addition to immutable ones. You use a `mQueue` similarly to how you use an immutable one, but instead of `enqueue`, you use the `+=` and `++=` operators to append. Also, on a mutable queue, the `dequeue` method will just remove the head element from the queue and return it. Here's an example: +{% tabs Queues_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=Queues_1 %} +~~~ scala> val queue = new scala.collection.mutable.Queue[String] queue: scala.collection.mutable.Queue[String] = Queue() scala> queue += "a" @@ -78,12 +111,34 @@ Scala provides mutable queues in addition to immutable ones. You use a `mQueue` res13: String = a scala> queue res14: scala.collection.mutable.Queue[String] = Queue(b, c) +~~~ +{% endtab %} +{% tab 'Scala 3' for=Queues_1 %} +~~~ + scala> val queue = scala.collection.mutable.Queue[String]() + queue: scala.collection.mutable.Queue[String] = Queue() + scala> queue += "a" + res10: queue.type = Queue(a) + scala> queue ++= List("b", "c") + res11: queue.type = Queue(a, b, c) + scala> queue + res12: scala.collection.mutable.Queue[String] = Queue(a, b, c) + scala> queue.dequeue + res13: String = a + scala> queue + res14: scala.collection.mutable.Queue[String] = Queue(b, c) +~~~ +{% endtab %} +{% endtabs %} ## Stacks A stack implements a data structure which allows to store and retrieve objects in a last-in-first-out (LIFO) fashion. It is supported by class [mutable.Stack](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/Stack.html). +{% tabs Stacks_1 class=tabs-scala-version %} +{% tab 'Scala 2' for=Stacks_1 %} +~~~ scala> val stack = new scala.collection.mutable.Stack[Int] stack: scala.collection.mutable.Stack[Int] = Stack() scala> stack.push(1) @@ -102,6 +157,31 @@ It is supported by class [mutable.Stack](https://www.scala-lang.org/api/{{ site. res10: Int = 2 scala> stack res11: scala.collection.mutable.Stack[Int] = Stack(1) +~~~ +{% endtab %} +{% tab 'Scala 3' for=Stacks_1 %} +~~~ + scala> val stack = scala.collection.mutable.Stack[Int]() + stack: scala.collection.mutable.Stack[Int] = Stack() + scala> stack.push(1) + res0: stack.type = Stack(1) + scala> stack + res1: scala.collection.mutable.Stack[Int] = Stack(1) + scala> stack.push(2) + res0: stack.type = Stack(1, 2) + scala> stack + res3: scala.collection.mutable.Stack[Int] = Stack(1, 2) + scala> stack.top + res8: Int = 2 + scala> stack + res9: scala.collection.mutable.Stack[Int] = Stack(1, 2) + scala> stack.pop + res10: Int = 2 + scala> stack + res11: scala.collection.mutable.Stack[Int] = Stack(1) +~~~ +{% endtab %} +{% endtabs %} ## Mutable ArraySeqs @@ -115,6 +195,9 @@ A hash table stores its elements in an underlying array, placing each item at a Hash sets and maps are used just like any other set or map. Here are some simple examples: +{% tabs Hash-Tables_1 %} +{% tab 'Scala 2 and 3' for=Hash-Tables_1 %} +~~~ scala> val map = scala.collection.mutable.HashMap.empty[Int,String] map: scala.collection.mutable.HashMap[Int,String] = Map() scala> map += (1 -> "make a web site") @@ -125,6 +208,9 @@ Hash sets and maps are used just like any other set or map. Here are some simple res44: String = make a web site scala> map contains 2 res46: Boolean = false +~~~ +{% endtab %} +{% endtabs %} Iteration over a hash table is not guaranteed to occur in any particular order. Iteration simply proceeds through the underlying array in whichever order it happens to be in. To get a guaranteed iteration order, use a _linked_ hash map or set instead of a regular one. A linked hash map or set is just like a regular hash map or set except that it also includes a linked list of the elements in the order they were added. Iteration over such a collection is always in the same order that the elements were initially added. @@ -151,6 +237,9 @@ A concurrent map can be accessed by several threads at once. In addition to the A mutable bit of type [mutable.BitSet](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/BitSet.html) set is just like an immutable one, except that it is modified in place. Mutable bit sets are slightly more efficient at updating than immutable ones, because they don't have to copy around `Long`s that haven't changed. +{% tabs BitSet_1 %} +{% tab 'Scala 2 and 3' for=BitSet_1 %} +~~~ scala> val bits = scala.collection.mutable.BitSet.empty bits: scala.collection.mutable.BitSet = BitSet() scala> bits += 1 @@ -159,3 +248,6 @@ A mutable bit of type [mutable.BitSet](https://www.scala-lang.org/api/{{ site.sc res50: bits.type = BitSet(1, 3) scala> bits res51: scala.collection.mutable.BitSet = BitSet(1, 3) +~~~ +{% endtab %} +{% endtabs %} From 8c2a412a8af10f3317b1ef0b4048f8ddb61e24bc Mon Sep 17 00:00:00 2001 From: Jamie Thompson Date: Tue, 4 Oct 2022 15:06:55 +0200 Subject: [PATCH 5/5] adjust indentation --- .../concrete-immutable-collection-classes.md | 136 +++++----- .../concrete-mutable-collection-classes.md | 240 +++++++++--------- _overviews/collections-2.13/maps.md | 22 +- _overviews/collections-2.13/sets.md | 16 +- 4 files changed, 209 insertions(+), 205 deletions(-) diff --git a/_overviews/collections-2.13/concrete-immutable-collection-classes.md b/_overviews/collections-2.13/concrete-immutable-collection-classes.md index 5964346cf3..d853880915 100644 --- a/_overviews/collections-2.13/concrete-immutable-collection-classes.md +++ b/_overviews/collections-2.13/concrete-immutable-collection-classes.md @@ -26,9 +26,9 @@ Whereas lists are constructed with the `::` operator, lazy lists are constructed {% tabs LazyList_1 %} {% tab 'Scala 2 and 3' for=LazyList_1 %} -~~~ - scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty - lazyList: scala.collection.immutable.LazyList[Int] = LazyList() +~~~scala +scala> val lazyList = 1 #:: 2 #:: 3 #:: LazyList.empty +lazyList: scala.collection.immutable.LazyList[Int] = LazyList() ~~~ {% endtab %} {% endtabs %} @@ -40,9 +40,9 @@ Below is a more complex example. It computes a lazy list that contains a Fibonac {% tabs LazyList_2 %} {% tab 'Scala 2 and 3' for=LazyList_2 %} -~~~ - scala> def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b) - fibFrom: (a: Int,b: Int)LazyList[Int] +~~~scala +scala> def fibFrom(a: Int, b: Int): LazyList[Int] = a #:: fibFrom(b, a + b) +fibFrom: (a: Int,b: Int)LazyList[Int] ~~~ {% endtab %} {% endtabs %} @@ -52,11 +52,11 @@ Here are the first few elements of the Fibonacci sequence starting with two ones {% tabs LazyList_3 %} {% tab 'Scala 2 and 3' for=LazyList_3 %} -~~~ - scala> val fibs = fibFrom(1, 1).take(7) - fibs: scala.collection.immutable.LazyList[Int] = LazyList() - scala> fibs.toList - res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13) +~~~scala +scala> val fibs = fibFrom(1, 1).take(7) +fibs: scala.collection.immutable.LazyList[Int] = LazyList() +scala> fibs.toList +res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13) ~~~ {% endtab %} {% endtabs %} @@ -75,7 +75,7 @@ ArraySeqs are built and updated just like any other sequence. {% tabs ArraySeq_1 %} {% tab 'Scala 2 and 3' for=ArraySeq_1 %} -~~~ +~~~scala scala> val arr = scala.collection.immutable.ArraySeq(1, 2, 3) arr: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 3) scala> val arr2 = arr :+ 4 @@ -91,7 +91,7 @@ operations create new ArraySeqs that differ from a given ArraySeq only in a sing {% tabs ArraySeq_2 %} {% tab 'Scala 2 and 3' for=ArraySeq_2 %} -~~~ +~~~scala scala> arr.updated(2, 4) res26: scala.collection.immutable.ArraySeq[Int] = ArraySeq(1, 2, 4) scala> arr @@ -118,15 +118,15 @@ Vectors are built and modified just like any other sequence. {% tabs Vector_1 %} {% tab 'Scala 2 and 3' for=Vector_1 %} -~~~ - scala> val vec = scala.collection.immutable.Vector.empty - vec: scala.collection.immutable.Vector[Nothing] = Vector() - scala> val vec2 = vec :+ 1 :+ 2 - vec2: scala.collection.immutable.Vector[Int] = Vector(1, 2) - scala> val vec3 = 100 +: vec2 - vec3: scala.collection.immutable.Vector[Int] = Vector(100, 1, 2) - scala> vec3(0) - res1: Int = 100 +~~~scala +scala> val vec = scala.collection.immutable.Vector.empty +vec: scala.collection.immutable.Vector[Nothing] = Vector() +scala> val vec2 = vec :+ 1 :+ 2 +vec2: scala.collection.immutable.Vector[Int] = Vector(1, 2) +scala> val vec3 = 100 +: vec2 +vec3: scala.collection.immutable.Vector[Int] = Vector(100, 1, 2) +scala> vec3(0) +res1: Int = 100 ~~~ {% endtab %} {% endtabs %} @@ -141,9 +141,9 @@ Because vectors strike a good balance between fast random selections and fast ra {% tabs Vector_2 %} {% tab 'Scala 2 and 3' for=Vector_2 %} -~~~ - scala> collection.immutable.IndexedSeq(1, 2, 3) - res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) +~~~scala +scala> collection.immutable.IndexedSeq(1, 2, 3) +res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) ~~~ {% endtab %} {% endtabs %} @@ -156,9 +156,9 @@ Here's how you can create an empty immutable queue: {% tabs Queue_1 %} {% tab 'Scala 2 and 3' for=Queue_1 %} -~~~ - scala> val empty = scala.collection.immutable.Queue[Int]() - empty: scala.collection.immutable.Queue[Int] = Queue() +~~~scala +scala> val empty = scala.collection.immutable.Queue[Int]() +empty: scala.collection.immutable.Queue[Int] = Queue() ~~~ {% endtab %} {% endtabs %} @@ -167,9 +167,9 @@ You can append an element to an immutable queue with `enqueue`: {% tabs Queue_2 %} {% tab 'Scala 2 and 3' for=Queue_2 %} -~~~ - scala> val has1 = empty.enqueue(1) - has1: scala.collection.immutable.Queue[Int] = Queue(1) +~~~scala +scala> val has1 = empty.enqueue(1) +has1: scala.collection.immutable.Queue[Int] = Queue(1) ~~~ {% endtab %} {% endtabs %} @@ -178,10 +178,10 @@ To append multiple elements to a queue, call `enqueueAll` with a collection as i {% tabs Queue_3 %} {% tab 'Scala 2 and 3' for=Queue_3 %} -~~~ - scala> val has123 = has1.enqueueAll(List(2, 3)) - has123: scala.collection.immutable.Queue[Int] - = Queue(1, 2, 3) +~~~scala +scala> val has123 = has1.enqueueAll(List(2, 3)) +has123: scala.collection.immutable.Queue[Int] + = Queue(1, 2, 3) ~~~ {% endtab %} {% endtabs %} @@ -190,10 +190,10 @@ To remove an element from the head of the queue, you use `dequeue`: {% tabs Queue_4 %} {% tab 'Scala 2 and 3' for=Queue_4 %} -~~~ - scala> val (element, has23) = has123.dequeue - element: Int = 1 - has23: scala.collection.immutable.Queue[Int] = Queue(2, 3) +~~~scala +scala> val (element, has23) = has123.dequeue +element: Int = 1 +has23: scala.collection.immutable.Queue[Int] = Queue(2, 3) ~~~ {% endtab %} {% endtabs %} @@ -206,11 +206,11 @@ A [Range](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collecti {% tabs Range_1 %} {% tab 'Scala 2 and 3' for=Range_1 %} -~~~ - scala> 1 to 3 - res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3) - scala> 5 to 14 by 3 - res3: scala.collection.immutable.Range = Range(5, 8, 11, 14) +~~~scala +scala> 1 to 3 +res2: scala.collection.immutable.Range.Inclusive = Range(1, 2, 3) +scala> 5 to 14 by 3 +res3: scala.collection.immutable.Range = Range(5, 8, 11, 14) ~~~ {% endtab %} {% endtabs %} @@ -219,9 +219,9 @@ If you want to create a range that is exclusive of its upper limit, then use the {% tabs Range_2 %} {% tab 'Scala 2 and 3' for=Range_2 %} -~~~ - scala> 1 until 3 - res2: scala.collection.immutable.Range = Range(1, 2) +~~~scala +scala> 1 until 3 +res2: scala.collection.immutable.Range = Range(1, 2) ~~~ {% endtab %} {% endtabs %} @@ -242,11 +242,11 @@ Scala provides implementations of immutable sets and maps that use a red-black t {% tabs Red-Black_1 %} {% tab 'Scala 2 and 3' for=Red-Black_1 %} -~~~ - scala> scala.collection.immutable.TreeSet.empty[Int] - res11: scala.collection.immutable.TreeSet[Int] = TreeSet() - scala> res11 + 1 + 3 + 3 - res12: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 3) +~~~scala +scala> scala.collection.immutable.TreeSet.empty[Int] +res11: scala.collection.immutable.TreeSet[Int] = TreeSet() +scala> res11 + 1 + 3 + 3 +res12: scala.collection.immutable.TreeSet[Int] = TreeSet(1, 3) ~~~ {% endtab %} {% endtabs %} @@ -263,15 +263,15 @@ Operations on bit sets are very fast. Testing for inclusion takes constant time. {% tabs BitSet_1 %} {% tab 'Scala 2 and 3' for=BitSet_1 %} -~~~ - scala> val bits = scala.collection.immutable.BitSet.empty - bits: scala.collection.immutable.BitSet = BitSet() - scala> val moreBits = bits + 3 + 4 + 4 - moreBits: scala.collection.immutable.BitSet = BitSet(3, 4) - scala> moreBits(3) - res26: Boolean = true - scala> moreBits(0) - res27: Boolean = false +~~~scala +scala> val bits = scala.collection.immutable.BitSet.empty +bits: scala.collection.immutable.BitSet = BitSet() +scala> val moreBits = bits + 3 + 4 + 4 +moreBits: scala.collection.immutable.BitSet = BitSet(3, 4) +scala> moreBits(3) +res26: Boolean = true +scala> moreBits(0) +res27: Boolean = false ~~~ {% endtab %} {% endtabs %} @@ -284,7 +284,7 @@ insertion order. {% tabs VectorMap_1 %} {% tab 'Scala 2 and 3' for=VectorMap_1 %} -~~~ +~~~scala scala> val vm = scala.collection.immutable.VectorMap.empty[Int, String] vm: scala.collection.immutable.VectorMap[Int,String] = VectorMap() @@ -310,12 +310,12 @@ A [ListMap](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/collec {% tabs ListMap_1 %} {% tab 'Scala 2 and 3' for=ListMap_1 %} -~~~ - scala> val map = scala.collection.immutable.ListMap(1->"one", 2->"two") - map: scala.collection.immutable.ListMap[Int,java.lang.String] = - Map(1 -> one, 2 -> two) - scala> map(2) - res30: String = "two" +~~~scala +scala> val map = scala.collection.immutable.ListMap(1->"one", 2->"two") +map: scala.collection.immutable.ListMap[Int,java.lang.String] = + Map(1 -> one, 2 -> two) +scala> map(2) +res30: String = "two" ~~~ {% endtab %} {% endtabs %} diff --git a/_overviews/collections-2.13/concrete-mutable-collection-classes.md b/_overviews/collections-2.13/concrete-mutable-collection-classes.md index e8acb12a6e..6978cd7486 100644 --- a/_overviews/collections-2.13/concrete-mutable-collection-classes.md +++ b/_overviews/collections-2.13/concrete-mutable-collection-classes.md @@ -20,15 +20,15 @@ An [ArrayBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/c {% tabs ArrayBuffer_1 %} {% tab 'Scala 2 and 3' for=ArrayBuffer_1 %} -~~~ - scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int] - buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() - scala> buf += 1 - res32: buf.type = ArrayBuffer(1) - scala> buf += 10 - res33: buf.type = ArrayBuffer(1, 10) - scala> buf.toArray - res34: Array[Int] = Array(1, 10) +~~~scala +scala> val buf = scala.collection.mutable.ArrayBuffer.empty[Int] +buf: scala.collection.mutable.ArrayBuffer[Int] = ArrayBuffer() +scala> buf += 1 +res32: buf.type = ArrayBuffer(1) +scala> buf += 10 +res33: buf.type = ArrayBuffer(1, 10) +scala> buf.toArray +res34: Array[Int] = Array(1, 10) ~~~ {% endtab %} {% endtabs %} @@ -39,15 +39,15 @@ A [ListBuffer](https://www.scala-lang.org/api/{{ site.scala-version }}/scala/col {% tabs ListBuffer_1 %} {% tab 'Scala 2 and 3' for=ListBuffer_1 %} -~~~ - scala> val buf = scala.collection.mutable.ListBuffer.empty[Int] - buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer() - scala> buf += 1 - res35: buf.type = ListBuffer(1) - scala> buf += 10 - res36: buf.type = ListBuffer(1, 10) - scala> buf.to(List) - res37: List[Int] = List(1, 10) +~~~scala +scala> val buf = scala.collection.mutable.ListBuffer.empty[Int] +buf: scala.collection.mutable.ListBuffer[Int] = ListBuffer() +scala> buf += 1 +res35: buf.type = ListBuffer(1) +scala> buf += 10 +res36: buf.type = ListBuffer(1, 10) +scala> buf.to(List) +res37: List[Int] = List(1, 10) ~~~ {% endtab %} {% endtabs %} @@ -58,27 +58,27 @@ Just like an array buffer is useful for building arrays, and a list buffer is us {% tabs StringBuilders_1 class=tabs-scala-version %} {% tab 'Scala 2' for=StringBuilders_1 %} -~~~ - scala> val buf = new StringBuilder - buf: StringBuilder = - scala> buf += 'a' - res38: buf.type = a - scala> buf ++= "bcdef" - res39: buf.type = abcdef - scala> buf.toString - res41: String = abcdef +~~~scala +scala> val buf = new StringBuilder +buf: StringBuilder = +scala> buf += 'a' +res38: buf.type = a +scala> buf ++= "bcdef" +res39: buf.type = abcdef +scala> buf.toString +res41: String = abcdef ~~~ {% endtab %} {% tab 'Scala 3' for=StringBuilders_1 %} -~~~ - scala> val buf = StringBuilder() - buf: StringBuilder = - scala> buf += 'a' - res38: buf.type = a - scala> buf ++= "bcdef" - res39: buf.type = abcdef - scala> buf.toString - res41: String = abcdef +~~~scala +scala> val buf = StringBuilder() +buf: StringBuilder = +scala> buf += 'a' +res38: buf.type = a +scala> buf ++= "bcdef" +res39: buf.type = abcdef +scala> buf.toString +res41: String = abcdef ~~~ {% endtab %} {% endtabs %} @@ -98,35 +98,35 @@ Scala provides mutable queues in addition to immutable ones. You use a `mQueue` {% tabs Queues_1 class=tabs-scala-version %} {% tab 'Scala 2' for=Queues_1 %} -~~~ - scala> val queue = new scala.collection.mutable.Queue[String] - queue: scala.collection.mutable.Queue[String] = Queue() - scala> queue += "a" - res10: queue.type = Queue(a) - scala> queue ++= List("b", "c") - res11: queue.type = Queue(a, b, c) - scala> queue - res12: scala.collection.mutable.Queue[String] = Queue(a, b, c) - scala> queue.dequeue - res13: String = a - scala> queue - res14: scala.collection.mutable.Queue[String] = Queue(b, c) +~~~scala +scala> val queue = new scala.collection.mutable.Queue[String] +queue: scala.collection.mutable.Queue[String] = Queue() +scala> queue += "a" +res10: queue.type = Queue(a) +scala> queue ++= List("b", "c") +res11: queue.type = Queue(a, b, c) +scala> queue +res12: scala.collection.mutable.Queue[String] = Queue(a, b, c) +scala> queue.dequeue +res13: String = a +scala> queue +res14: scala.collection.mutable.Queue[String] = Queue(b, c) ~~~ {% endtab %} {% tab 'Scala 3' for=Queues_1 %} -~~~ - scala> val queue = scala.collection.mutable.Queue[String]() - queue: scala.collection.mutable.Queue[String] = Queue() - scala> queue += "a" - res10: queue.type = Queue(a) - scala> queue ++= List("b", "c") - res11: queue.type = Queue(a, b, c) - scala> queue - res12: scala.collection.mutable.Queue[String] = Queue(a, b, c) - scala> queue.dequeue - res13: String = a - scala> queue - res14: scala.collection.mutable.Queue[String] = Queue(b, c) +~~~scala +scala> val queue = scala.collection.mutable.Queue[String]() +queue: scala.collection.mutable.Queue[String] = Queue() +scala> queue += "a" +res10: queue.type = Queue(a) +scala> queue ++= List("b", "c") +res11: queue.type = Queue(a, b, c) +scala> queue +res12: scala.collection.mutable.Queue[String] = Queue(a, b, c) +scala> queue.dequeue +res13: String = a +scala> queue +res14: scala.collection.mutable.Queue[String] = Queue(b, c) ~~~ {% endtab %} {% endtabs %} @@ -138,47 +138,47 @@ It is supported by class [mutable.Stack](https://www.scala-lang.org/api/{{ site. {% tabs Stacks_1 class=tabs-scala-version %} {% tab 'Scala 2' for=Stacks_1 %} -~~~ - scala> val stack = new scala.collection.mutable.Stack[Int] - stack: scala.collection.mutable.Stack[Int] = Stack() - scala> stack.push(1) - res0: stack.type = Stack(1) - scala> stack - res1: scala.collection.mutable.Stack[Int] = Stack(1) - scala> stack.push(2) - res0: stack.type = Stack(1, 2) - scala> stack - res3: scala.collection.mutable.Stack[Int] = Stack(1, 2) - scala> stack.top - res8: Int = 2 - scala> stack - res9: scala.collection.mutable.Stack[Int] = Stack(1, 2) - scala> stack.pop - res10: Int = 2 - scala> stack - res11: scala.collection.mutable.Stack[Int] = Stack(1) +~~~scala +scala> val stack = new scala.collection.mutable.Stack[Int] +stack: scala.collection.mutable.Stack[Int] = Stack() +scala> stack.push(1) +res0: stack.type = Stack(1) +scala> stack +res1: scala.collection.mutable.Stack[Int] = Stack(1) +scala> stack.push(2) +res0: stack.type = Stack(1, 2) +scala> stack +res3: scala.collection.mutable.Stack[Int] = Stack(1, 2) +scala> stack.top +res8: Int = 2 +scala> stack +res9: scala.collection.mutable.Stack[Int] = Stack(1, 2) +scala> stack.pop +res10: Int = 2 +scala> stack +res11: scala.collection.mutable.Stack[Int] = Stack(1) ~~~ {% endtab %} {% tab 'Scala 3' for=Stacks_1 %} -~~~ - scala> val stack = scala.collection.mutable.Stack[Int]() - stack: scala.collection.mutable.Stack[Int] = Stack() - scala> stack.push(1) - res0: stack.type = Stack(1) - scala> stack - res1: scala.collection.mutable.Stack[Int] = Stack(1) - scala> stack.push(2) - res0: stack.type = Stack(1, 2) - scala> stack - res3: scala.collection.mutable.Stack[Int] = Stack(1, 2) - scala> stack.top - res8: Int = 2 - scala> stack - res9: scala.collection.mutable.Stack[Int] = Stack(1, 2) - scala> stack.pop - res10: Int = 2 - scala> stack - res11: scala.collection.mutable.Stack[Int] = Stack(1) +~~~scala +scala> val stack = scala.collection.mutable.Stack[Int]() +stack: scala.collection.mutable.Stack[Int] = Stack() +scala> stack.push(1) +res0: stack.type = Stack(1) +scala> stack +res1: scala.collection.mutable.Stack[Int] = Stack(1) +scala> stack.push(2) +res0: stack.type = Stack(1, 2) +scala> stack +res3: scala.collection.mutable.Stack[Int] = Stack(1, 2) +scala> stack.top +res8: Int = 2 +scala> stack +res9: scala.collection.mutable.Stack[Int] = Stack(1, 2) +scala> stack.pop +res10: Int = 2 +scala> stack +res11: scala.collection.mutable.Stack[Int] = Stack(1) ~~~ {% endtab %} {% endtabs %} @@ -197,17 +197,17 @@ Hash sets and maps are used just like any other set or map. Here are some simple {% tabs Hash-Tables_1 %} {% tab 'Scala 2 and 3' for=Hash-Tables_1 %} -~~~ - scala> val map = scala.collection.mutable.HashMap.empty[Int,String] - map: scala.collection.mutable.HashMap[Int,String] = Map() - scala> map += (1 -> "make a web site") - res42: map.type = Map(1 -> make a web site) - scala> map += (3 -> "profit!") - res43: map.type = Map(1 -> make a web site, 3 -> profit!) - scala> map(1) - res44: String = make a web site - scala> map contains 2 - res46: Boolean = false +~~~scala +scala> val map = scala.collection.mutable.HashMap.empty[Int,String] +map: scala.collection.mutable.HashMap[Int,String] = Map() +scala> map += (1 -> "make a web site") +res42: map.type = Map(1 -> make a web site) +scala> map += (3 -> "profit!") +res43: map.type = Map(1 -> make a web site, 3 -> profit!) +scala> map(1) +res44: String = make a web site +scala> map contains 2 +res46: Boolean = false ~~~ {% endtab %} {% endtabs %} @@ -239,15 +239,15 @@ A mutable bit of type [mutable.BitSet](https://www.scala-lang.org/api/{{ site.sc {% tabs BitSet_1 %} {% tab 'Scala 2 and 3' for=BitSet_1 %} -~~~ - scala> val bits = scala.collection.mutable.BitSet.empty - bits: scala.collection.mutable.BitSet = BitSet() - scala> bits += 1 - res49: bits.type = BitSet(1) - scala> bits += 3 - res50: bits.type = BitSet(1, 3) - scala> bits - res51: scala.collection.mutable.BitSet = BitSet(1, 3) +~~~scala +scala> val bits = scala.collection.mutable.BitSet.empty +bits: scala.collection.mutable.BitSet = BitSet() +scala> bits += 1 +res49: bits.type = BitSet(1) +scala> bits += 3 +res50: bits.type = BitSet(1, 3) +scala> bits +res51: scala.collection.mutable.BitSet = BitSet(1, 3) ~~~ {% endtab %} {% endtabs %} diff --git a/_overviews/collections-2.13/maps.md b/_overviews/collections-2.13/maps.md index a8fb77971e..030850e835 100644 --- a/_overviews/collections-2.13/maps.md +++ b/_overviews/collections-2.13/maps.md @@ -110,8 +110,10 @@ Assume further that `f` has no side-effects, so invoking it again with the same {% tabs cache-creation %} {% tab 'Scala 2 and 3' for=cache-creation %} - scala> val cache = collection.mutable.Map[String, String]() - cache: scala.collection.mutable.Map[String,String] = Map() +```scala +scala> val cache = collection.mutable.Map[String, String]() +cache: scala.collection.mutable.Map[String,String] = Map() +``` {% endtab %} {% endtabs %} @@ -119,13 +121,15 @@ You can now create a more efficient caching version of the `f` function: {% tabs cache-usage %} {% tab 'Scala 2 and 3' for=cache-usage %} - scala> def cachedF(s: String): String = cache.getOrElseUpdate(s, f(s)) - cachedF: (s: String)String - scala> cachedF("abc") - taking my time. - res3: String = cba - scala> cachedF("abc") - res4: String = cba +```scala +scala> def cachedF(s: String): String = cache.getOrElseUpdate(s, f(s)) +cachedF: (s: String)String +scala> cachedF("abc") +taking my time. +res3: String = cba +scala> cachedF("abc") +res4: String = cba +``` {% endtab %} {% endtabs %} diff --git a/_overviews/collections-2.13/sets.md b/_overviews/collections-2.13/sets.md index 40b4cc8d46..a57814ffd1 100644 --- a/_overviews/collections-2.13/sets.md +++ b/_overviews/collections-2.13/sets.md @@ -20,7 +20,7 @@ For example: {% tabs sets_1 %} {% tab 'Scala 2 and 3' for=sets_1 %} -``` +```scala scala> val fruit = Set("apple", "orange", "peach", "banana") fruit: scala.collection.immutable.Set[java.lang.String] = Set(apple, orange, peach, banana) scala> fruit("peach") @@ -91,7 +91,7 @@ The choice of the method names `+=` and `-=` means that very similar code can wo {% tabs sets_2 %} {% tab 'Scala 2 and 3' for=sets_2 %} -``` +```scala scala> var s = Set(1, 2, 3) s: scala.collection.immutable.Set[Int] = Set(1, 2, 3) scala> s += 4 @@ -106,7 +106,7 @@ We used `+=` and `-=` on a `var` of type `immutable.Set`. A statement such as `s {% tabs sets_3 %} {% tab 'Scala 2 and 3' for=sets_3 %} -``` +```scala scala> val s = collection.mutable.Set(1, 2, 3) s: scala.collection.mutable.Set[Int] = Set(1, 2, 3) scala> s += 4 @@ -137,7 +137,7 @@ To create an empty [TreeSet](https://www.scala-lang.org/api/current/scala/collec {% tabs sorted-sets_1 %} {% tab 'Scala 2 and 3' for=sorted-sets_1 %} -``` +```scala scala> val myOrdering = Ordering.fromLessThan[String](_ > _) myOrdering: scala.math.Ordering[String] = ... ``` @@ -148,7 +148,7 @@ Then, to create an empty tree set with that ordering, use: {% tabs sorted-sets_2 %} {% tab 'Scala 2 and 3' for=sorted-sets_2 %} -``` +```scala scala> TreeSet.empty(myOrdering) res1: scala.collection.immutable.TreeSet[String] = TreeSet() ``` @@ -159,7 +159,7 @@ Or you can leave out the ordering argument but give an element type for the empt {% tabs sorted-sets_3 %} {% tab 'Scala 2 and 3' for=sorted-sets_3 %} -``` +```scala scala> TreeSet.empty[String] res2: scala.collection.immutable.TreeSet[String] = TreeSet() ``` @@ -170,7 +170,7 @@ If you create new sets from a tree-set (for instance by concatenation or filteri {% tabs sorted-sets_4 %} {% tab 'Scala 2 and 3' for=sorted-sets_4 %} -``` +```scala scala> res2 + "one" + "two" + "three" + "four" res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two) ``` @@ -181,7 +181,7 @@ Sorted sets also support ranges of elements. For instance, the `range` method re {% tabs sorted-sets_5 %} {% tab 'Scala 2 and 3' for=sorted-sets_5 %} -``` +```scala scala> res3.range("one", "two") res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three) scala> res3 rangeFrom "three"