From bc076cdada2eac9e9a6ecf4b655bf259ada89721 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Mon, 24 Jun 2013 13:16:58 +1000 Subject: [PATCH 01/17] added a little korean document to test --- ko/overviews/collections/introduction.md | 94 ++++++++++++++++++++++++ ko/overviews/index.md | 12 +++ overviews/collections/introduction.md | 2 +- overviews/index.md | 2 +- 4 files changed, 108 insertions(+), 2 deletions(-) create mode 100755 ko/overviews/collections/introduction.md create mode 100755 ko/overviews/index.md diff --git a/ko/overviews/collections/introduction.md b/ko/overviews/collections/introduction.md new file mode 100755 index 0000000000..31d2e3f045 --- /dev/null +++ b/ko/overviews/collections/introduction.md @@ -0,0 +1,94 @@ +--- +layout: overview-large +title: 컬렉션 소개 + +disqus: true + +partof: collections +num: 1 +language: ja +--- + +**Martin Odersky와 Lex Spoon** + +대부분의 사람들에게 있어 스칼라 2.8의 가장 중요한 변화는 새 컬렉션 프레임워크일 것이다. +스칼라에는 예전부터 컬렉션이 포함되어 있었다(실제 새 프레임워크도 이전 컬렉션과 상당부분 호환성이 있다). +하지만 다양한 컬렉션 유형을 포괄하는 일반적이면서 균일한 프레임워크를 제공하는 것은 스칼라 2.8 부터이다. + +Even though the additions to collections are subtle at first glance, +the changes they can provoke in your programming style can be +profound. In fact, quite often it's as if you work on a higher-level +with the basic building blocks of a program being whole collections +instead of their elements. This new style of programming requires some +adaptation. Fortunately, the adaptation is helped by several nice +properties of the new Scala collections. They are easy to use, +concise, safe, fast, universal. + +**Easy to use:** A small vocabulary of 20-50 methods is +enough to solve most collection problems in a couple of operations. No +need to wrap your head around complicated looping structures or +recursions. Persistent collections and side-effect-free operations mean +that you need not worry about accidentally corrupting existing +collections with new data. Interference between iterators and +collection updates is eliminated. + +**Concise:** You can achieve with a single word what used to +take one or several loops. You can express functional operations with +lightweight syntax and combine operations effortlessly, so that the result +feels like a custom algebra. + +**Safe:** This one has to be experienced to sink in. The +statically typed and functional nature of Scala's collections means +that the overwhelming majority of errors you might make are caught at +compile-time. The reason is that (1) the collection operations +themselves are heavily used and therefore well +tested. (2) the usages of the collection operation make inputs and +output explicit as function parameters and results. (3) These explicit +inputs and outputs are subject to static type checking. The bottom line +is that the large majority of misuses will manifest themselves as type +errors. It's not at all uncommon to have programs of several hundred +lines run at first try. + +**Fast:** Collection operations are tuned and optimized in the +libraries. As a result, using collections is typically quite +efficient. You might be able to do a little bit better with carefully +hand-tuned data structures and operations, but you might also do a lot +worse by making some suboptimal implementation decisions along the +way. What's more, collections have been recently adapted to parallel +execution on multi-cores. Parallel collections support the same +operations as sequential ones, so no new operations need to be learned +and no code needs to be rewritten. You can turn a sequential collection into a +parallel one simply by invoking the `par` method. + +**Universal:** Collections provide the same operations on +any type where it makes sense to do so. So you can achieve a lot with +a fairly small vocabulary of operations. For instance, a string is +conceptually a sequence of characters. Consequently, in Scala +collections, strings support all sequence operations. The same holds +for arrays. + +**Example:** Here's one line of code that demonstrates many of the +advantages of Scala's collections. + + val (minors, adults) = people partition (_.age < 18) + +It's immediately clear what this operation does: It partitions a +collection of `people` into `minors` and `adults` depending on +their age. Because the `partition` method is defined in the root +collection type `TraversableLike`, this code works for any kind of +collection, including arrays. The resulting `minors` and `adults` +collections will be of the same type as the `people` collection. + +This code is much more concise than the one to three loops required for +traditional collection processing (three loops for an array, because +the intermediate results need to be buffered somewhere else). Once +you have learned the basic collection vocabulary you will also find +writing this code is much easier and safer than writing explicit +loops. Furthermore, the `partition` operation is quite fast, and will +get even faster on parallel collections on multi-cores. (Parallel +collections have been released +as part of Scala 2.9.) + +This document provides an in depth discussion of the APIs of the +Scala collections classes from a user perspective. They take you on +a tour of all the fundamental classes and the methods they define. \ No newline at end of file diff --git a/ko/overviews/index.md b/ko/overviews/index.md new file mode 100755 index 0000000000..f3a8578a0b --- /dev/null +++ b/ko/overviews/index.md @@ -0,0 +1,12 @@ +--- +layout: guides-index +language: ko +title: 가이드 및 개요 +--- + +
+

핵심 필수요소들...

+
+ +{% include localized-overview-index.txt %} + diff --git a/overviews/collections/introduction.md b/overviews/collections/introduction.md index ae57e0167f..290ab7d337 100644 --- a/overviews/collections/introduction.md +++ b/overviews/collections/introduction.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 1 -languages: [ja] +languages: [ja, ko] --- **Martin Odersky, and Lex Spoon** diff --git a/overviews/index.md b/overviews/index.md index dba3e7dcc8..0e78d19971 100644 --- a/overviews/index.md +++ b/overviews/index.md @@ -1,7 +1,7 @@ --- layout: guides-index title: Guides and Overviews -languages: [es, ja] +languages: [es, ja, ko] ---
From 48276dd982b4a3773b61ade3e55b352c574090a5 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Mon, 24 Jun 2013 13:39:51 +1000 Subject: [PATCH 02/17] changed the language to ko and translated some paragraphs --- ko/overviews/collections/introduction.md | 32 ++++++++---------------- ko/overviews/index.md | 1 + 2 files changed, 12 insertions(+), 21 deletions(-) diff --git a/ko/overviews/collections/introduction.md b/ko/overviews/collections/introduction.md index 31d2e3f045..65006f8ed9 100755 --- a/ko/overviews/collections/introduction.md +++ b/ko/overviews/collections/introduction.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 1 -language: ja +language: ko --- **Martin Odersky와 Lex Spoon** @@ -15,29 +15,19 @@ language: ja 스칼라에는 예전부터 컬렉션이 포함되어 있었다(실제 새 프레임워크도 이전 컬렉션과 상당부분 호환성이 있다). 하지만 다양한 컬렉션 유형을 포괄하는 일반적이면서 균일한 프레임워크를 제공하는 것은 스칼라 2.8 부터이다. -Even though the additions to collections are subtle at first glance, -the changes they can provoke in your programming style can be -profound. In fact, quite often it's as if you work on a higher-level -with the basic building blocks of a program being whole collections -instead of their elements. This new style of programming requires some -adaptation. Fortunately, the adaptation is helped by several nice -properties of the new Scala collections. They are easy to use, -concise, safe, fast, universal. +처음 봤을 땐 컬렉션에 추가된 내용이 어떤 것인지 잘 알기 어려울 수 있다. 하지만, 그 변화가 여러분의 프로그래밍 +스타일에 미칠 영향은 심오하다. 실제로, 컬렉션의 개별 원소 보다는 전체 컬렉션을 프로그램의 기본 구성 요소로 +사용해 더 상위 레벨에서 작업하는 것 처럼 느끼게 될 것이다. 이런 프로그래밍 스타일에 익숙해지려면 적응이 필요하다. +다행히 새 스칼라 컬렉션이 제공하는 몇몇 특징으로 인해 쉽게 적응할 수 있다. 새 스칼라 컬렉션은 쓰기 쉽고, +간결하며, 안전하고, 일반적이다. -**Easy to use:** A small vocabulary of 20-50 methods is -enough to solve most collection problems in a couple of operations. No -need to wrap your head around complicated looping structures or -recursions. Persistent collections and side-effect-free operations mean -that you need not worry about accidentally corrupting existing -collections with new data. Interference between iterators and -collection updates is eliminated. +**사용 용이성:** 대부분의 경우 컬렉션과 관련된 문제를 몇 연산을 거쳐 해결하는데 필요한 메소드는 20-50개 정도이다. 복잡하게 루프를 돌거나 재귀 호출을 하기 위해 끙끙거릴 필요가 없다. +영속적인 컬렉션과 부작용이 없는 연산을 사용하면 실수로 기존 컬렉션을 오염시킬까 염려할 필요가 없다. 이터레이터와 컬렉션 업데이트간의 간섭도 없다. -**Concise:** You can achieve with a single word what used to -take one or several loops. You can express functional operations with -lightweight syntax and combine operations effortlessly, so that the result -feels like a custom algebra. +**간결성:** 하나 이상의 루프를 통해 작업해야 했던 것을 한 단어로 수행할 수 있다. 간결한 문법으로 연산을 표현할 수 있고, 각 연산을 힘들이지 않고 조합할 수 있다. 따라서 +컬렉션 전용 대수식을 사용하는 것 같은 느낌을 받게될 것이다. -**Safe:** This one has to be experienced to sink in. The +**안전성:** This one has to be experienced to sink in. The statically typed and functional nature of Scala's collections means that the overwhelming majority of errors you might make are caught at compile-time. The reason is that (1) the collection operations diff --git a/ko/overviews/index.md b/ko/overviews/index.md index f3a8578a0b..a790542aae 100755 --- a/ko/overviews/index.md +++ b/ko/overviews/index.md @@ -9,4 +9,5 @@ title: 가이드 및 개요
{% include localized-overview-index.txt %} + From 7787aa4fe3de201efbaffa0533ea14e6e5dd4a87 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Mon, 24 Jun 2013 16:04:24 +1000 Subject: [PATCH 03/17] end of 1st translation @ introduction.md --- ko/overviews/collections/introduction.md | 74 ++++-------- ko/overviews/collections/overview.md | 145 +++++++++++++++++++++++ overviews/collections/overview.md | 2 +- 3 files changed, 172 insertions(+), 49 deletions(-) create mode 100755 ko/overviews/collections/overview.md diff --git a/ko/overviews/collections/introduction.md b/ko/overviews/collections/introduction.md index 65006f8ed9..79ffee4016 100755 --- a/ko/overviews/collections/introduction.md +++ b/ko/overviews/collections/introduction.md @@ -19,7 +19,7 @@ language: ko 스타일에 미칠 영향은 심오하다. 실제로, 컬렉션의 개별 원소 보다는 전체 컬렉션을 프로그램의 기본 구성 요소로 사용해 더 상위 레벨에서 작업하는 것 처럼 느끼게 될 것이다. 이런 프로그래밍 스타일에 익숙해지려면 적응이 필요하다. 다행히 새 스칼라 컬렉션이 제공하는 몇몇 특징으로 인해 쉽게 적응할 수 있다. 새 스칼라 컬렉션은 쓰기 쉽고, -간결하며, 안전하고, 일반적이다. +간결하며, 안전하고, 범용이다. **사용 용이성:** 대부분의 경우 컬렉션과 관련된 문제를 몇 연산을 거쳐 해결하는데 필요한 메소드는 20-50개 정도이다. 복잡하게 루프를 돌거나 재귀 호출을 하기 위해 끙끙거릴 필요가 없다. 영속적인 컬렉션과 부작용이 없는 연산을 사용하면 실수로 기존 컬렉션을 오염시킬까 염려할 필요가 없다. 이터레이터와 컬렉션 업데이트간의 간섭도 없다. @@ -27,58 +27,36 @@ language: ko **간결성:** 하나 이상의 루프를 통해 작업해야 했던 것을 한 단어로 수행할 수 있다. 간결한 문법으로 연산을 표현할 수 있고, 각 연산을 힘들이지 않고 조합할 수 있다. 따라서 컬렉션 전용 대수식을 사용하는 것 같은 느낌을 받게될 것이다. -**안전성:** This one has to be experienced to sink in. The -statically typed and functional nature of Scala's collections means -that the overwhelming majority of errors you might make are caught at -compile-time. The reason is that (1) the collection operations -themselves are heavily used and therefore well -tested. (2) the usages of the collection operation make inputs and -output explicit as function parameters and results. (3) These explicit -inputs and outputs are subject to static type checking. The bottom line -is that the large majority of misuses will manifest themselves as type -errors. It's not at all uncommon to have programs of several hundred -lines run at first try. +**안전성:** 이를 제대로 인식하려면 경험이 필요하다. 스칼라 컬렉션은 정적 타이핑과 함수적 특성을 가지기 때문에 +프로그래머가 저지를 수 있는 오류의 대부분을 컴파일시 잡아낼 수 있을 것이다. 이유는 (1) 컬렉션 연산을 많이 사용하기 +때문에 충분한 테스트가 있루어질 수 있고, (2) 컬렉션 연산을 사용할 때 입력과 출력을 매개 변수로 넘기는 함수와 결과값으로 +명확히 해야 하며, (3) 이런 명시적인 입/출력이 정적인 타입 검사를 거쳐야 한다는 점 때문이다. 요약하면, 대부분의 잘못된 +사용은 타입 오류라는 형태로 나타나게 될 것이라는 점이다. 수백줄 짜리 코드가 첫 시도시 실행되는 경우를 보는 것도 전혀 +드문 일이 아니다. -**Fast:** Collection operations are tuned and optimized in the -libraries. As a result, using collections is typically quite -efficient. You might be able to do a little bit better with carefully -hand-tuned data structures and operations, but you might also do a lot -worse by making some suboptimal implementation decisions along the -way. What's more, collections have been recently adapted to parallel -execution on multi-cores. Parallel collections support the same -operations as sequential ones, so no new operations need to be learned -and no code needs to be rewritten. You can turn a sequential collection into a -parallel one simply by invoking the `par` method. +**속도:** 라이브라리 안의 컬렉션 연산은 최적화와 미세조정이 이루어져 있다. 그 결과 컬렉션을 사용하는 것은 +보통 꽤 효율적이다. 손으로 직접 주의깊게 미세조정을 거친 데이터 구조와 연산을 사용하면 조금 더 나은 결과를 +얻을 수도 있을 것이다. 하지만 구현 도중에 최적이 아닌 선택을 하거나 해서 훨씬 더 나쁜 결과를 가져올 수도 있다. +더 나아가, 최근에는 다중코어 시스템에서 병렬로 수행되도록 하는 컬렉션이 도입되었다. 병렬 컬렉션은 순차적 컬렉션과 +동일한 연산을 지원한다. 따라서 새로운 연산을 배우거나 코드를 재작성할 필요가 없다. 순차적 컬렉션을 병렬 켤렉션으로 +변경하려면 단지 `par` 메소드를 호출하기만 하면 된다. -**Universal:** Collections provide the same operations on -any type where it makes sense to do so. So you can achieve a lot with -a fairly small vocabulary of operations. For instance, a string is -conceptually a sequence of characters. Consequently, in Scala -collections, strings support all sequence operations. The same holds -for arrays. +**범용:** 어떤 컬렉션 연산이든, 그 연산을 제공하는 것이 합리적인 모든 컬렉션에서 이를 제공하게 되어 있다. +따라서 아주 작은 연산들만 알고 있어도 많은 일을 할 수 있다. 예를 들어 문자열은 개념적으로 문자의 시퀀스이다. 따라서, +스칼라 컬렉션의 문자열은 모든 시퀀스 연산을 지원한다. 배열도 마찬가지이다. -**Example:** Here's one line of code that demonstrates many of the -advantages of Scala's collections. +**예제:** 다음 코드는 스칼라 컬렉션의 장점을 보여준다. val (minors, adults) = people partition (_.age < 18) -It's immediately clear what this operation does: It partitions a -collection of `people` into `minors` and `adults` depending on -their age. Because the `partition` method is defined in the root -collection type `TraversableLike`, this code works for any kind of -collection, including arrays. The resulting `minors` and `adults` -collections will be of the same type as the `people` collection. +이 코드가 하는 일은 직접적이며 분명하다. `people`의 컬렉션을 나이에 따라 `minors`과 `adults`로 구획한다. +`partition` 메소드는 루트 컬렉션 타입인 `TraversableLike`에 구현되어 있다. 따라서 배열을 포함한 모든 컬렉션에서 이 코드가 +동작할 수 있다. 결과로 나오는 `minors`과 `adults`는 `people` 컬렉션과 같은 타입이 된다. -This code is much more concise than the one to three loops required for -traditional collection processing (three loops for an array, because -the intermediate results need to be buffered somewhere else). Once -you have learned the basic collection vocabulary you will also find -writing this code is much easier and safer than writing explicit -loops. Furthermore, the `partition` operation is quite fast, and will -get even faster on parallel collections on multi-cores. (Parallel -collections have been released -as part of Scala 2.9.) +전통적인 컬렉션 처리를 사용하는 경우 루프를 최대 세 개 사용해야 한다는 점과 비교해 보면 이 코드는 매우 간결하다(배열을 +사용하는 경우 중간 결과를 다른곳에 버퍼링하기 위해 루프가 세 개 필요하다). 일단 컬렉션의 기본 어휘를 배우고 나면, +직접 루프를 도는 것보다, 이렇게 코드를 작성하는 것이 더 쉽고 안전하다는 사실을 알게 될 것이다. 또한, `partition` 연산은 +꽤 빠르며, 다중코어에서 병렬 컬렉션으로 수행한다면 훨씬 더 빨라진다(병렬 컬렉션은 스칼라 2.9에 포함되어 배포되었다). -This document provides an in depth discussion of the APIs of the -Scala collections classes from a user perspective. They take you on -a tour of all the fundamental classes and the methods they define. \ No newline at end of file +이 문서는 스칼라 컬렉션 클래스의 API를 사용자 관점에서 자세히 논의한다. 이제 모든 기반 클래스와 그 안에 정의된 메소드에 대해 +여행을 떠나 보자. \ No newline at end of file diff --git a/ko/overviews/collections/overview.md b/ko/overviews/collections/overview.md new file mode 100755 index 0000000000..3fca9bcbc7 --- /dev/null +++ b/ko/overviews/collections/overview.md @@ -0,0 +1,145 @@ +--- +layout: overview-large +title: 가변성 컬렉션과 불변성 컬렉션 + +disqus: true + +partof: collections +num: 2 +language: ko +--- + +스칼라 컬렉션에서는 구조적으로 불변성(immutable)인 컬렉션과 가변성(mutable)인 컬렉션을 +구분한다. + +Scala collections systematically distinguish between mutable and +immutable collections. A _mutable_ collection can be updated or +extended in place. This means you can change, add, or remove elements +of a collection as a side effect. _Immutable_ collections, by +contrast, never change. You have still operations that simulate +additions, removals, or updates, but those operations will in each +case return a new collection and leave the old collection unchanged. + +All collection classes are found in the package `scala.collection` or +one of its sub-packages `mutable`, `immutable`, and `generic`. Most +collection classes needed by client code exist in three variants, +which are located in packages `scala.collection`, +`scala.collection.immutable`, and `scala.collection.mutable`, +respectively. Each variant has different characteristics with respect +to mutability. + +A collection in package `scala.collection.immutable` is guaranteed to +be immutable for everyone. Such a collection will never change after +it is created. Therefore, you can rely on the fact that accessing the +same collection value repeatedly at different points in time will +always yield a collection with the same elements. + +A collection in package `scala.collection.mutable` is known to have +some operations that change the collection in place. So dealing with +mutable collection means you need to understand which code changes +which collection when. + +A collection in package `scala.collection` can be either mutable or +immutable. For instance, [collection.IndexedSeq\[T\]](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html) +is a superclass of both [collection.immutable.IndexedSeq\[T\]](http://www.scala-lang.org/api/current/scala/collection/immutable/IndexedSeq.html) +and +[collection.mutable.IndexedSeq\[T\]](http://www.scala-lang.org/api/current/scala/collection/mutable/IndexedSeq.html) +Generally, the root collections in +package `scala.collection` define the same interface as the immutable +collections, and the mutable collections in package +`scala.collection.mutable` typically add some side-effecting +modification operations to this immutable interface. + +The difference between root collections and immutable collections is +that clients of an immutable collection have a guarantee that nobody +can mutate the collection, whereas clients of a root collection only +promise not to change the collection themselves. Even though the +static type of such a collection provides no operations for modifying +the collection, it might still be possible that the run-time type is a +mutable collection which can be changed by other clients. + +By default, Scala always picks immutable collections. For instance, if +you just write `Set` without any prefix or without having imported +`Set` from somewhere, you get an immutable set, and if you write +`Iterable` you get an immutable iterable collection, because these +are the default bindings imported from the `scala` package. To get +the mutable default versions, you need to write explicitly +`collection.mutable.Set`, or `collection.mutable.Iterable`. + +A useful convention if you want to use both mutable and immutable +versions of collections is to import just the package +`collection.mutable`. + + import scala.collection.mutable + +Then a word like `Set` without a prefix still refers to an an immutable collection, +whereas `mutable.Set` refers to the mutable counterpart. + +The last package in the collection hierarchy is `collection.generic`. This +package contains building blocks for implementing +collections. Typically, collection classes defer the implementations +of some of their operations to classes in `generic`. Users of the +collection framework on the other hand should need to refer to +classes in `generic` only in exceptional circumstances. + +For convenience and backwards compatibility some important types have +aliases in the `scala` package, so you can use them by their simple +names without needing an import. An example is the `List` type, which +can be accessed alternatively as + + scala.collection.immutable.List // that's where it is defined + scala.List // via the alias in the scala package + List // because scala._ + // is always automatically imported + +Other types so aliased are +[Traversable](http://www.scala-lang.org/api/current/scala/collection/Traversable.html), [Iterable](http://www.scala-lang.org/api/current/scala/collection/Iterable.html), [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html), [IndexedSeq](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html), [Iterator](http://www.scala-lang.org/api/current/scala/collection/Iterator.html), [Stream](http://www.scala-lang.org/api/current/scala/collection/immutable/Stream.html), [Vector](http://www.scala-lang.org/api/current/scala/collection/immutable/Vector.html), [StringBuilder](http://www.scala-lang.org/api/current/scala/collection/mutable/StringBuilder.html), and [Range](http://www.scala-lang.org/api/current/scala/collection/immutable/Range.html). + +The following figure shows all collections in package +`scala.collection`. These are all high-level abstract classes or traits, which +generally have mutable as well as immutable implementations. + +[]({{ site.baseurl }}/resources/images/collections.png) + +The following figure shows all collections in package `scala.collection.immutable`. + +[]({{ site.baseurl }}/resources/images/collections.immutable.png) + +And the following figure shows all collections in package `scala.collection.mutable`. + +[]({{ site.baseurl }}/resources/images/collections.mutable.png) + +(All three figures were generated by Matthias at decodified.com). + +## An Overview of the Collections API ## + +The most important collection classes are shown in the figures above. There is quite a bit of commonality shared by all these classes. For instance, every kind of collection can be created by the same uniform syntax, writing the collection class name followed by its elements: + + Traversable(1, 2, 3) + Iterable("x", "y", "z") + Map("x" -> 24, "y" -> 25, "z" -> 26) + Set(Color.red, Color.green, Color.blue) + SortedSet("hello", "world") + Buffer(x, y, z) + IndexedSeq(1.0, 2.0) + LinearSeq(a, b, c) + +The same principle also applies for specific collection implementations, such as: + + List(1, 2, 3) + HashMap("x" -> 24, "y" -> 25, "z" -> 26) + +All these collections get displayed with `toString` in the same way they are written above. + +All collections support the API provided by `Traversable`, but specialize types wherever this makes sense. For instance the `map` method in class `Traversable` returns another `Traversable` as its result. But this result type is overridden in subclasses. For instance, calling `map` on a `List` yields again a `List`, calling it on a `Set` yields again a `Set` and so on. + + scala> List(1, 2, 3) map (_ + 1) + res0: List[Int] = List(2, 3, 4) + scala> Set(1, 2, 3) map (_ * 2) + res0: Set[Int] = Set(2, 4, 6) + +This behavior which is implemented everywhere in the collections libraries is called the _uniform return type principle_. + +Most of the classes in the collections hierarchy exist in three variants: root, mutable, and immutable. The only exception is the Buffer trait which only exists as a mutable collection. + +In the following, we will review these classes one by one. \ No newline at end of file diff --git a/overviews/collections/overview.md b/overviews/collections/overview.md index bb18ec2b17..64517c8d42 100644 --- a/overviews/collections/overview.md +++ b/overviews/collections/overview.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 2 -languages: [ja] +languages: [ja, ko] --- Scala collections systematically distinguish between mutable and From 4a07a11dc034a73c13050b78e50b8b14f2cdc153 Mon Sep 17 00:00:00 2001 From: enshahar Date: Mon, 24 Jun 2013 23:15:01 +1000 Subject: [PATCH 04/17] =?UTF-8?q?-=EC=BB=AC=EB=A0=89=EC=85=98=20=EB=AA=A9?= =?UTF-8?q?=EB=A1=9D=EC=9D=B4=20=EC=A0=9C=EB=8C=80=EB=A1=9C=20=EC=B2=98?= =?UTF-8?q?=EB=A6=AC=EB=90=98=EA=B2=8C=20ko/core=EB=A5=BC=20=EC=B6=94?= =?UTF-8?q?=EA=B0=80=ED=95=A8=20-collection/introduction.md=20=ED=87=B4?= =?UTF-8?q?=EA=B3=A0=20-=ED=95=9C=EA=B8=80=20=EC=95=84=EC=9D=B4=EC=BD=98?= =?UTF-8?q?=EC=9D=B4=20=EB=B3=B4=EC=9D=B4=EA=B2=8C=20overviews/core=20?= =?UTF-8?q?=EC=95=84=EB=9E=98=EC=9D=98=20=EC=98=81=EB=AC=B8=20=EC=86=8C?= =?UTF-8?q?=EC=8A=A4=EB=A5=BC=20=EC=88=98=EC=A0=95=ED=95=A8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/introduction.md | 84 +++++++++++++----------- ko/overviews/core/collections.md | 7 ++ 2 files changed, 54 insertions(+), 37 deletions(-) mode change 100755 => 100644 ko/overviews/collections/introduction.md create mode 100644 ko/overviews/core/collections.md diff --git a/ko/overviews/collections/introduction.md b/ko/overviews/collections/introduction.md old mode 100755 new mode 100644 index 79ffee4016..e65d97905e --- a/ko/overviews/collections/introduction.md +++ b/ko/overviews/collections/introduction.md @@ -9,54 +9,64 @@ num: 1 language: ko --- -**Martin Odersky와 Lex Spoon** +**마틴 오더스키(Martin Odesky)와 렉스 스푼(Lex Spoon) 씀** 대부분의 사람들에게 있어 스칼라 2.8의 가장 중요한 변화는 새 컬렉션 프레임워크일 것이다. -스칼라에는 예전부터 컬렉션이 포함되어 있었다(실제 새 프레임워크도 이전 컬렉션과 상당부분 호환성이 있다). -하지만 다양한 컬렉션 유형을 포괄하는 일반적이면서 균일한 프레임워크를 제공하는 것은 스칼라 2.8 부터이다. +스칼라에는 예전부터 컬렉션이 포함되어 있었다(실제 새 프레임워크도 이전 컬렉션과 상당부분 호환성이 있다). 하지만 다양한 컬렉션 유형을 포괄하는 일반적이면서 균일한 프레임워크를 제공하는 것은 스칼라 2.8 부터이다. -처음 봤을 땐 컬렉션에 추가된 내용이 어떤 것인지 잘 알기 어려울 수 있다. 하지만, 그 변화가 여러분의 프로그래밍 -스타일에 미칠 영향은 심오하다. 실제로, 컬렉션의 개별 원소 보다는 전체 컬렉션을 프로그램의 기본 구성 요소로 -사용해 더 상위 레벨에서 작업하는 것 처럼 느끼게 될 것이다. 이런 프로그래밍 스타일에 익숙해지려면 적응이 필요하다. -다행히 새 스칼라 컬렉션이 제공하는 몇몇 특징으로 인해 쉽게 적응할 수 있다. 새 스칼라 컬렉션은 쓰기 쉽고, -간결하며, 안전하고, 범용이다. +처음 봤을 땐 컬렉션에 추가된 내용이 잘 알기 어려울 정도로 작게 느껴질 수도 있다. 하지만, 그 +변화는 여러분의 프로그래밍 스타일에 큰 영향을 끼칠 것이다. 실제로, 컬렉션의 개별 원소 보다는 +전체 컬렉션을 프로그램의 기본 구성 요소로 사용하는 더 높은 레벨에서 작업하는 느낌을 받을 수 +있다. 이런 프로그래밍 스타일에 익숙해지려면 적응이 필요하다. 다행히 새 스칼라 컬렉션이 +제공하는 몇몇 특징 덕분에 더 쉽게 적응할 수 있다. 새 스칼라 컬렉션은 쓰기 쉽고, +간결하며, 안전하고, 빠른 데다가, 범용이다. -**사용 용이성:** 대부분의 경우 컬렉션과 관련된 문제를 몇 연산을 거쳐 해결하는데 필요한 메소드는 20-50개 정도이다. 복잡하게 루프를 돌거나 재귀 호출을 하기 위해 끙끙거릴 필요가 없다. -영속적인 컬렉션과 부작용이 없는 연산을 사용하면 실수로 기존 컬렉션을 오염시킬까 염려할 필요가 없다. 이터레이터와 컬렉션 업데이트간의 간섭도 없다. +**간편성:** 대부분의 경우 컬렉션과 관련된 문제를 해결하기 위해 필요한 메소드는 수는 +20-50개 정도이며 두세 연산을 조합하여 해결 가능하다. 복잡하게 루프를 돌거나 재귀 호출을 +하기 위해 골머리를 썩힐 필요가 없다. 영속적인 컬렉션과 부작용이 없는 연산을 사용하면 실수로 +기존 컬렉션을 오염시킬 염려가 없다. 반복자와 컬렉션 업데이트간의 간섭도 없다. -**간결성:** 하나 이상의 루프를 통해 작업해야 했던 것을 한 단어로 수행할 수 있다. 간결한 문법으로 연산을 표현할 수 있고, 각 연산을 힘들이지 않고 조합할 수 있다. 따라서 -컬렉션 전용 대수식을 사용하는 것 같은 느낌을 받게될 것이다. +**간결성:** 하나 이상의 루프가 필요했던 작업을 한 단어로 수행할 수 있다. 간결한 문법으로 +연산을 표현할 수 있고, 각 연산을 힘들이지 않고 조합할 수 있다. 따라서 컬렉션 전용으로 고안된 +대수식을 사용하는 것 같은 느낌을 받게될 것이다. -**안전성:** 이를 제대로 인식하려면 경험이 필요하다. 스칼라 컬렉션은 정적 타이핑과 함수적 특성을 가지기 때문에 -프로그래머가 저지를 수 있는 오류의 대부분을 컴파일시 잡아낼 수 있을 것이다. 이유는 (1) 컬렉션 연산을 많이 사용하기 -때문에 충분한 테스트가 있루어질 수 있고, (2) 컬렉션 연산을 사용할 때 입력과 출력을 매개 변수로 넘기는 함수와 결과값으로 -명확히 해야 하며, (3) 이런 명시적인 입/출력이 정적인 타입 검사를 거쳐야 한다는 점 때문이다. 요약하면, 대부분의 잘못된 -사용은 타입 오류라는 형태로 나타나게 될 것이라는 점이다. 수백줄 짜리 코드가 첫 시도시 실행되는 경우를 보는 것도 전혀 -드문 일이 아니다. +**안전성:** 경험해 보지 않고 이 부분을 알아채기는 어렵다. 스칼라 컬렉션은 정적 타이핑과 +함수적 특성을 가지기 때문에 프로그래머가 저지를 수 있는 오류의 대부분을 컴파일시 잡아낼 +수 있다. 이유는 (1) 컬렉션 연산을 많이 사용하기 때문에 연산에 대해 충분한 테스트가 되어 있고, +(2) 컬렉션 연산을 사용할 때 입력과 출력을 매개 변수로 넘기는 함수와 결과값으로 명확히 해야 +하며, (3) 이런 명시적인 입/출력이 정적인 타입 검사를 거쳐야 한다는 점 때문이다. 요약하면, +대부분의 잘못된 사용은 타입 오류라로 나타나게 된다. 수백줄 짜리 코드가 첫 시도시 실행되는 +경우도 그리 드물지 않다. -**속도:** 라이브라리 안의 컬렉션 연산은 최적화와 미세조정이 이루어져 있다. 그 결과 컬렉션을 사용하는 것은 -보통 꽤 효율적이다. 손으로 직접 주의깊게 미세조정을 거친 데이터 구조와 연산을 사용하면 조금 더 나은 결과를 -얻을 수도 있을 것이다. 하지만 구현 도중에 최적이 아닌 선택을 하거나 해서 훨씬 더 나쁜 결과를 가져올 수도 있다. -더 나아가, 최근에는 다중코어 시스템에서 병렬로 수행되도록 하는 컬렉션이 도입되었다. 병렬 컬렉션은 순차적 컬렉션과 -동일한 연산을 지원한다. 따라서 새로운 연산을 배우거나 코드를 재작성할 필요가 없다. 순차적 컬렉션을 병렬 켤렉션으로 -변경하려면 단지 `par` 메소드를 호출하기만 하면 된다. +**속도:** 라이브라리 안의 컬렉션 연산은 최적화와 미세조정이 이루어져 있다. 그 결과 컬렉션을 +사용하는 것은 일반적으로 아주 효율적이다. 손으로 직접 주의깊게 미세조정을 거친 데이터 구조와 +연산을 사용하면 조금 더 나은 결과를 얻을 수도 있을 것이다. 하지만 구현 도중에 최적이 아닌 +선택을 하거나 해서 훨씬 더 나쁜 결과를 가져올 수도 있다. 더 나아가, 최근에는 다중코어 +시스템에서 병렬로 수행되는 컬렉션이 도입되었다. 병렬 컬렉션은 순차적 컬렉션과 동일한 연산을 +지원한다. 따라서 새로운 연산을 배우거나 코드를 재작성할 필요가 없다. 순차적 컬렉션을 병렬 +컬렉션으로 변경하려면 단지 `par` 메소드를 호출하기만 하면 된다. -**범용:** 어떤 컬렉션 연산이든, 그 연산을 제공하는 것이 합리적인 모든 컬렉션에서 이를 제공하게 되어 있다. -따라서 아주 작은 연산들만 알고 있어도 많은 일을 할 수 있다. 예를 들어 문자열은 개념적으로 문자의 시퀀스이다. 따라서, -스칼라 컬렉션의 문자열은 모든 시퀀스 연산을 지원한다. 배열도 마찬가지이다. +**범용:** 어떤 컬렉션 연산이든, 가능한 모든 컬렉션에서 이를 제공하게 되어 있다. 따라서 알고 +있는 연산의 갯수가 적어도 많은 일을 할 수 있다. 예를 들어 문자열은 개념적으로 문자의 +시퀀스이다. 따라서, 스칼라 컬렉션의 문자열은 모든 시퀀스 연산을 지원한다. 배열도 마찬가지이다. -**예제:** 다음 코드는 스칼라 컬렉션의 장점을 보여준다. +**예제:** 다음 코드는 스칼라 컬렉션의 여러 장점을 보여준다. val (minors, adults) = people partition (_.age < 18) -이 코드가 하는 일은 직접적이며 분명하다. `people`의 컬렉션을 나이에 따라 `minors`과 `adults`로 구획한다. -`partition` 메소드는 루트 컬렉션 타입인 `TraversableLike`에 구현되어 있다. 따라서 배열을 포함한 모든 컬렉션에서 이 코드가 -동작할 수 있다. 결과로 나오는 `minors`과 `adults`는 `people` 컬렉션과 같은 타입이 된다. +이 코드가 하는 일은 직접적이며 분명하다. `people`의 컬렉션을 나이에 따라 `minors`과 +`adults`로 구획한다. `partition` 메소드는 최상위 컬렉션 타입인 `TraversableLike`에 +구현되어 있다. 따라서 배열을 포함한 모든 컬렉션에서 이 코드가 동작할 수 있다. 결과로 +나오는 `minors`과 `adults`는 `people` 컬렉션과 같은 타입이 된다. -전통적인 컬렉션 처리를 사용하는 경우 루프를 최대 세 개 사용해야 한다는 점과 비교해 보면 이 코드는 매우 간결하다(배열을 -사용하는 경우 중간 결과를 다른곳에 버퍼링하기 위해 루프가 세 개 필요하다). 일단 컬렉션의 기본 어휘를 배우고 나면, -직접 루프를 도는 것보다, 이렇게 코드를 작성하는 것이 더 쉽고 안전하다는 사실을 알게 될 것이다. 또한, `partition` 연산은 -꽤 빠르며, 다중코어에서 병렬 컬렉션으로 수행한다면 훨씬 더 빨라진다(병렬 컬렉션은 스칼라 2.9에 포함되어 배포되었다). +전통적인 컬렉션 처리를 사용하는 경우 루프를 최대 세 개 사용해야 한다는 점과 비교해 보면 이 +코드는 매우 간결하다(배열을 사용하는 경우 중간 결과를 다른곳에 버퍼링하기 위해 루프가 세 개 +필요하다). 일단 컬렉션의 기본 어휘를 배우고 나면, 직접 루프를 도는 것보다 이렇게 코드를 +작성하는 편이 더 쉽고 안전하다는 사실을 알게 될 것이다. 또한, `partition` 연산은 +꽤 빠르며, 다중코어에서 병렬 컬렉션으로 수행한다면 훨씬 더 빨라진다(병렬 컬렉션은 +스칼라 2.9에 포함되어 배포되었다). -이 문서는 스칼라 컬렉션 클래스의 API를 사용자 관점에서 자세히 논의한다. 이제 모든 기반 클래스와 그 안에 정의된 메소드에 대해 -여행을 떠나 보자. \ No newline at end of file +이 문서는 스칼라 컬렉션 클래스의 API를 사용자 관점에서 자세히 논의한다. 이제 모든 기반 +클래스와 그 안에 정의된 메소드에 대해 여행을 떠나 보자. + +번역: 오현석(enshahar@gmail.com) diff --git a/ko/overviews/core/collections.md b/ko/overviews/core/collections.md new file mode 100644 index 0000000000..91f34cc416 --- /dev/null +++ b/ko/overviews/core/collections.md @@ -0,0 +1,7 @@ +--- +layout: overview +overview: collections +partof: collections +language: ko +title: Scala コレクションライブラリ +--- From d1d3c3bd1dcf34acc1e7d764c6cc69e030feb0a3 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 00:40:15 +1000 Subject: [PATCH 05/17] =?UTF-8?q?traversable=20trait=20=EC=84=A4=EB=AA=85?= =?UTF-8?q?=20=EB=B2=88=EC=97=AD=20=EC=8B=9C=EC=9E=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/trait-traversable.md | 114 ++++++++++++++++++ overviews/collections/trait-traversable.md | 4 +- 2 files changed, 116 insertions(+), 2 deletions(-) create mode 100644 ko/overviews/collections/trait-traversable.md diff --git a/ko/overviews/collections/trait-traversable.md b/ko/overviews/collections/trait-traversable.md new file mode 100644 index 0000000000..fea7029c19 --- /dev/null +++ b/ko/overviews/collections/trait-traversable.md @@ -0,0 +1,114 @@ +--- +layout: overview-large +title: Traversable 트레잇 + +disqus: true + +partof: collections +num: 3 +language: ko +--- + +컬렉션 계층의 최상위에는 트레잇 `Traversable(방문 가능)`이 있다. 이 트레잇에 +있는 유일한 추상적인 연산이 바로 `foreach`이다. + + def foreach[U](f: Elem => U) + +`Traversable`을 구현하는 컬렉션 클래스는 단지 이 메소드만 정의하면 된다. +다른 메소드는 자동으로 `Traversable`에서 상속된다. + +`foreach` 메소드는 컬렉션의 모든 원소를 방문하면서 주어진 연산 f를 각 원소에 +적용한다. 이 연산 f의 타입은 `Elem => U`로 `Elem`은 컬렉션의 원소의 +타입이며, `U`는 임의의 결과 타입이다. `f`는 부작용을 위해 호출된다. 따라서 +f가 내놓는 결과값은 `foreach`가 무시한다. + +`Traversable`에는 여러 구체적 메소드가 정의되어 있다. 이들은 아래 표에 나열되어 있다. 각 메소드들은 다음과 같은 분류에 속한다. + +* **합치기**, `++`는 두 방문가능한 객체를 함께 이어붙이거나, 한 반복자의 모든 원소를 다른 방문가능 객체에 추가한다. +* **맵** 연산인 `map`, `flatMap`, `collect`는 인자로 넘겨진 함수를 컬렉션 원소에 적용한 결과로 이루어진 새 컬렉션을 만들어낸다. +* **Conversions** `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap`, which turn a `Traversable` collection into something more specific. All these conversions return their receiver argument unchanged if the run-time type of the collection already matches the demanded collection type. For instance, applying `toList` to a list will yield the list itself. +* **Copying operations** `copyToBuffer` and `copyToArray`. As their names imply, these copy collection elements to a buffer or array, respectively. +* **Size info** operations `isEmpty`, `nonEmpty`, `size`, and `hasDefiniteSize`: Traversable collections can be finite or infinite. An example of an infinite traversable collection is the stream of natural numbers `Stream.from(0)`. The method `hasDefiniteSize` indicates whether a collection is possibly infinite. If `hasDefiniteSize` returns true, the collection is certainly finite. If it returns false, the collection has not been not fully elaborated yet, so it might be infinite or finite. +* **Element retrieval** operations `head`, `last`, `headOption`, `lastOption`, and `find`. These select the first or last element of a collection, or else the first element matching a condition. Note, however, that not all collections have a well-defined meaning of what "first" and "last" means. For instance, a hash set might store elements according to their hash keys, which might change from run to run. In that case, the "first" element of a hash set could also be different for every run of a program. A collection is _ordered_ if it always yields its elements in the same order. Most collections are ordered, but some (_e.g._ hash sets) are not-- dropping the ordering gives a little bit of extra efficiency. Ordering is often essential to give reproducible tests and to help in debugging. That's why Scala collections give ordered alternatives for all collection types. For instance, the ordered alternative for `HashSet` is `LinkedHashSet`. +* **Sub-collection retrieval operations** `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter`. These all return some sub-collection identified by an index range or some predicate. +* **Subdivision operations** `splitAt`, `span`, `partition`, `groupBy`, which split the elements of this collection into several sub-collections. +* **Element tests** `exists`, `forall`, `count` which test collection elements with a given predicate. +* **Folds** `foldLeft`, `foldRight`, `/:`, `:\`, `reduceLeft`, `reduceRight` which apply a binary operation to successive elements. +* **Specific folds** `sum`, `product`, `min`, `max`, which work on collections of specific types (numeric or comparable). +* **String** operations `mkString`, `addString`, `stringPrefix`, which give alternative ways of converting a collection to a string. +* **View** operations, consisting of two overloaded variants of the `view` method. A view is a collection that's evaluated lazily. You'll learn more about views in [later](#Views). + +### Operations in Class Traversable ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Abstract Method:** | | +| `xs foreach f` |Executes function `f` for every element of `xs`.| +| **Addition:** | | +| `xs ++ ys` |A collection consisting of the elements of both `xs` and `ys`. `ys` is a [TraversableOnce](http://www.scala-lang.org/api/current/scala/collection/TraversableOnce.html) collection, i.e., either a [Traversable](http://www.scala-lang.org/api/current/scala/collection/Traversable.html) or an [Iterator](http://www.scala-lang.org/api/current/scala/collection/Iterator.html).| +| **Maps:** | | +| `xs map f` |The collection obtained from applying the function f to every element in `xs`.| +| `xs flatMap f` |The collection obtained from applying the collection-valued function `f` to every element in `xs` and concatenating the results.| +| `xs collect f` |The collection obtained from applying the partial function `f` to every element in `xs` for which it is defined and collecting the results.| +| **Conversions:** | | +| `xs.toArray` |Converts the collection to an array. | +| `xs.toList` |Converts the collection to a list. | +| `xs.toIterable` |Converts the collection to an iterable. | +| `xs.toSeq` |Converts the collection to a sequence. | +| `xs.toIndexedSeq` |Converts the collection to an indexed sequence. | +| `xs.toStream` |Converts the collection to a lazily computed stream.| +| `xs.toSet` |Converts the collection to a set. | +| `xs.toMap` |Converts the collection of key/value pairs to a map. If the collection does not have pairs as elements, calling this operation results in a static type error.| +| **Copying:** | | +| `xs copyToBuffer buf` |Copies all elements of the collection to buffer `buf`.| +| `xs copyToArray(arr, s, n)`|Copies at most `n` elements of the collection to array `arr` starting at index `s`. The last two arguments are optional.| +| **Size info:** | | +| `xs.isEmpty` |Tests whether the collection is empty. | +| `xs.nonEmpty` |Tests whether the collection contains elements. | +| `xs.size` |The number of elements in the collection. | +| `xs.hasDefiniteSize` |True if `xs` is known to have finite size. | +| **Element Retrieval:** | | +| `xs.head` |The first element of the collection (or, some element, if no order is defined).| +| `xs.headOption` |The first element of `xs` in an option value, or None if `xs` is empty.| +| `xs.last` |The last element of the collection (or, some element, if no order is defined).| +| `xs.lastOption` |The last element of `xs` in an option value, or None if `xs` is empty.| +| `xs find p` |An option containing the first element in `xs` that satisfies `p`, or `None` is no element qualifies.| +| **Subcollections:** | | +| `xs.tail` |The rest of the collection except `xs.head`. | +| `xs.init` |The rest of the collection except `xs.last`. | +| `xs slice (from, to)` |A collection consisting of elements in some index range of `xs` (from `from` up to, and excluding `to`).| +| `xs take n` |A collection consisting of the first `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).| +| `xs drop n` |The rest of the collection except `xs take n`.| +| `xs takeWhile p` |The longest prefix of elements in the collection that all satisfy `p`.| +| `xs dropWhile p` |The collection without the longest prefix of elements that all satisfy `p`.| +| `xs filter p` |The collection consisting of those elements of xs that satisfy the predicate `p`.| +| `xs withFilter p` |A non-strict filter of this collection. Subsequent calls to `map`, `flatMap`, `foreach`, and `withFilter` will only apply to those elements of `xs` for which the condition `p` is true.| +| `xs filterNot p` |The collection consisting of those elements of `xs` that do not satisfy the predicate `p`.| +| **Subdivisions:** | | +| `xs splitAt n` |Split `xs` at a position, giving the pair of collections `(xs take n, xs drop n)`.| +| `xs span p` |Split `xs` according to a predicate, giving the pair of collections `(xs takeWhile p, xs.dropWhile p)`.| +| `xs partition p` |Split `xs` into a pair of two collections; one with elements that satisfy the predicate `p`, the other with elements that do not, giving the pair of collections `(xs filter p, xs.filterNot p)`| +| `xs groupBy f` |Partition `xs` into a map of collections according to a discriminator function `f`.| +| **Element Conditions:** | | +| `xs forall p` |A boolean indicating whether the predicate `p` holds for all elements of `xs`.| +| `xs exists p` |A boolean indicating whether the predicate `p` holds for some element in `xs`.| +| `xs count p` |The number of elements in `xs` that satisfy the predicate `p`.| +| **Folds:** | | +| `(z /: xs)(op)` |Apply binary operation `op` between successive elements of `xs`, going left to right and starting with `z`.| +| `(xs :\ z)(op)` |Apply binary operation `op` between successive elements of `xs`, going right to left and starting with `z`.| +| `xs.foldLeft(z)(op)` |Same as `(z /: xs)(op)`.| +| `xs.foldRight(z)(op)` |Same as `(xs :\ z)(op)`.| +| `xs reduceLeft op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going left to right.| +| `xs reduceRight op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going right to left.| +| **Specific Folds:** | | +| `xs.sum` |The sum of the numeric element values of collection `xs`.| +| `xs.product` |The product of the numeric element values of collection `xs`.| +| `xs.min` |The minimum of the ordered element values of collection `xs`.| +| `xs.max` |The maximum of the ordered element values of collection `xs`.| +| **Strings:** | | +| `xs addString (b, start, sep, end)`|Adds a string to `StringBuilder` `b` that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.| +| `xs mkString (start, sep, end)`|Converts the collection to a string that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.| +| `xs.stringPrefix` |The collection name at the beginning of the string returned from `xs.toString`.| +| **Views:** | | +| `xs.view` |Produces a view over `xs`.| +| `xs view (from, to)` |Produces a view that represents the elements in some index range of `xs`.| diff --git a/overviews/collections/trait-traversable.md b/overviews/collections/trait-traversable.md index 09ae378b4b..10526e88c1 100644 --- a/overviews/collections/trait-traversable.md +++ b/overviews/collections/trait-traversable.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 3 -languages: [ja] +languages: [ja, ko] --- At the top of the collection hierarchy is trait `Traversable`. Its only abstract operation is `foreach`: @@ -106,4 +106,4 @@ The `foreach` method is meant to traverse all elements of the collection, and ap | `xs.stringPrefix` |The collection name at the beginning of the string returned from `xs.toString`.| | **Views:** | | | `xs.view` |Produces a view over `xs`.| -| `xs view (from, to)` |Produces a view that represents the elements in some index range of `xs`.| \ No newline at end of file +| `xs view (from, to)` |Produces a view that represents the elements in some index range of `xs`.| From c77bd3f4a86170e915661c5f16cc5181b1b614df Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 15:27:21 +1000 Subject: [PATCH 06/17] translated some. --- ko/overviews/collections/trait-traversable.md | 54 ++++++++++--------- 1 file changed, 29 insertions(+), 25 deletions(-) diff --git a/ko/overviews/collections/trait-traversable.md b/ko/overviews/collections/trait-traversable.md index fea7029c19..aaf217e9be 100644 --- a/ko/overviews/collections/trait-traversable.md +++ b/ko/overviews/collections/trait-traversable.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: Traversable 트레잇 +title: Traversable() 트레잇 disqus: true @@ -9,7 +9,7 @@ num: 3 language: ko --- -컬렉션 계층의 최상위에는 트레잇 `Traversable(방문 가능)`이 있다. 이 트레잇에 +컬렉션 계층의 최상위에는 트레잇 `Traversable(순회가능)`이 있다. 이 트레잇에 있는 유일한 추상적인 연산이 바로 `foreach`이다. def foreach[U](f: Elem => U) @@ -22,29 +22,33 @@ language: ko 타입이며, `U`는 임의의 결과 타입이다. `f`는 부작용을 위해 호출된다. 따라서 f가 내놓는 결과값은 `foreach`가 무시한다. -`Traversable`에는 여러 구체적 메소드가 정의되어 있다. 이들은 아래 표에 나열되어 있다. 각 메소드들은 다음과 같은 분류에 속한다. +`Traversable`에는 여러 구체적 메소드가 정의되어 있다. 이들은 아래 표에 나열되어 있다. +각 메소드들은 다음과 같은 분류에 속한다. -* **합치기**, `++`는 두 방문가능한 객체를 함께 이어붙이거나, 한 반복자의 모든 원소를 다른 방문가능 객체에 추가한다. +* **병합** 연산 `++`는 두 방문가능한 객체를 함께 이어붙이거나, 한 반복자의 모든 원소를 다른 방문가능 객체에 추가한다. * **맵** 연산인 `map`, `flatMap`, `collect`는 인자로 넘겨진 함수를 컬렉션 원소에 적용한 결과로 이루어진 새 컬렉션을 만들어낸다. -* **Conversions** `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap`, which turn a `Traversable` collection into something more specific. All these conversions return their receiver argument unchanged if the run-time type of the collection already matches the demanded collection type. For instance, applying `toList` to a list will yield the list itself. -* **Copying operations** `copyToBuffer` and `copyToArray`. As their names imply, these copy collection elements to a buffer or array, respectively. -* **Size info** operations `isEmpty`, `nonEmpty`, `size`, and `hasDefiniteSize`: Traversable collections can be finite or infinite. An example of an infinite traversable collection is the stream of natural numbers `Stream.from(0)`. The method `hasDefiniteSize` indicates whether a collection is possibly infinite. If `hasDefiniteSize` returns true, the collection is certainly finite. If it returns false, the collection has not been not fully elaborated yet, so it might be infinite or finite. -* **Element retrieval** operations `head`, `last`, `headOption`, `lastOption`, and `find`. These select the first or last element of a collection, or else the first element matching a condition. Note, however, that not all collections have a well-defined meaning of what "first" and "last" means. For instance, a hash set might store elements according to their hash keys, which might change from run to run. In that case, the "first" element of a hash set could also be different for every run of a program. A collection is _ordered_ if it always yields its elements in the same order. Most collections are ordered, but some (_e.g._ hash sets) are not-- dropping the ordering gives a little bit of extra efficiency. Ordering is often essential to give reproducible tests and to help in debugging. That's why Scala collections give ordered alternatives for all collection types. For instance, the ordered alternative for `HashSet` is `LinkedHashSet`. -* **Sub-collection retrieval operations** `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter`. These all return some sub-collection identified by an index range or some predicate. -* **Subdivision operations** `splitAt`, `span`, `partition`, `groupBy`, which split the elements of this collection into several sub-collections. -* **Element tests** `exists`, `forall`, `count` which test collection elements with a given predicate. -* **Folds** `foldLeft`, `foldRight`, `/:`, `:\`, `reduceLeft`, `reduceRight` which apply a binary operation to successive elements. -* **Specific folds** `sum`, `product`, `min`, `max`, which work on collections of specific types (numeric or comparable). -* **String** operations `mkString`, `addString`, `stringPrefix`, which give alternative ways of converting a collection to a string. -* **View** operations, consisting of two overloaded variants of the `view` method. A view is a collection that's evaluated lazily. You'll learn more about views in [later](#Views). +* **변환** 연산인 `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap` 등은 `Traversable` +컬렉션을 더 구체적인 데이터 구조로 변환한다. 런타임에 수신자가 이미 변환 결과 컬렉션 타입이었다면, 각 변환 메소드는 수신자를 그대로 반환한다. 예를 들어 리스트에 `toList`를 적용하면 그 리스트 자신이 반환된다. +* **복사** 연산으로 `copyToBuffer`와 `copyToArray`가 있다. 이름이 말하는데로 각각 컬렉션 원소를 버퍼나 배열에 복사한다. +* **크기 정보** 연산 `isEmpty`, `nonEmpty`, `size`, `hasDefiniteSize`: 순회가능한 컬렉션은 유한할 수도 있고, 무한할 수도 있다. +무한한 순회가능한 컬렉션의 예를 들자면 자연수의 스트림 `Stream.from(0)`이 있다. 메소드 `hasDefiniteSize`는 컬렉션이 무한 컬렉션일 가능성이 있는지를 알려준다. `hasDefiniteSize`가 참을 반환하면 컬렉션이 유한하다는 것이 확실하다. 하지만, 컬렉션이 내부 원소를 아직 완전히 계산해 채우지 않은 경우에는 거짓을 반환하기 때문에, 거짓을 반환한다 해도 유한할 수도 있고 무한할 수도 있다. +* **원소 가져오기** 연산 `head`, `last`, `headOption`, `lastOption`, `find`등은 컬렉션의 첫 원소나 마지막 원소를 선택하거나, 조건을 만족하는 첫 원소를 선택한다. 하지만 모든 컬렉션에서 "첫번째"나 "마지막"의 의미가 잘 정의되어 있는 것은 아니라는 점에 유의하라. 예를 들어 해시 집합은 해시값에 따라 원소를 저장하는데, 이 해시값은 매 실행시마다 변할 수 있다. 이런 경우 해시 집합의 +"첫번째" 원소는 프로그램이 실행될 때마다 바뀔 수 있다. 어떤 컬렉션이 항상 같은 순서로 원소를 표시한다면 이를 _순서있다_ 고 한다. 대부분의 컬렉션은 순서가 있으나, 일부(_e.g._ 해시 집합)는 그렇지 않다 -- 이들은 순서를 포기하는 대신 효율을 택한 것이다. 동일한 테스트를 반복하거나, 디버깅을 할 때 때로 순서가 꼭 필요하다. 이 때문에 모든 스칼라 컬렉션 타입에는 순서가 있는 대체물이 반드시 존재한다. 예를 들어 `HashSet`에 순서가 부여된 것은 `LinkedHashSet`이다. +* **부분 컬렉션 가져오기** 연산에는 `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter` 등이 있다. 이들은 모두 어떤 첨자 범위나 술어 함수에 의해 식별되는 부분 컬렉션을 반환한다. +* **분할** 연산인 `splitAt`, `span`, `partition`, `groupBy` 등은 대상 컬렉션의 원소를 구분해서 여러 부분 컬렉션으로 나눈다. +* **원소 테스트** 연산 `exists`, `forall`, `count`는 주어진 술어 함수를 가지고 컬렉션 원소들을 검사한다. +* **폴드** 연산 `foldLeft`, `foldRight`, `/:`, `:\`, `reduceLeft`, `reduceRight`는 인접한 두 원소에 대해 이항 연산자(binary operator)를 반복적용한다. +* **특정 폴드** `sum`, `product`, `min`, `max`는 특정 타입(비교가능하거나 수)의 컬렉션에만 작용한다. +* **문자열** 연산 `mkString`, `addString`, `stringPrefix`는 컬렉션을 문자열로 바꾸는 여러가지 방법을 제공한다. +* **뷰** 연산은 `view` 메소드를 오버로딩한 두 메소드이다. 뷰는 지연 계산될 수 있는 컬렉션이다. 뷰에 대해서는 [나중에](#Views) 다룰 것이다. -### Operations in Class Traversable ### +### Traversable에 정의되어 있는 연산들 ### -| WHAT IT IS | WHAT IT DOES | +| 쓰는법 | 하는일 | | ------ | ------ | -| **Abstract Method:** | | -| `xs foreach f` |Executes function `f` for every element of `xs`.| -| **Addition:** | | +| **추상 메소드:** | | +| `xs foreach f` |함수 `f`를 `xs`의 모든 원소에 적용한다.| +| **병합:** | | | `xs ++ ys` |A collection consisting of the elements of both `xs` and `ys`. `ys` is a [TraversableOnce](http://www.scala-lang.org/api/current/scala/collection/TraversableOnce.html) collection, i.e., either a [Traversable](http://www.scala-lang.org/api/current/scala/collection/Traversable.html) or an [Iterator](http://www.scala-lang.org/api/current/scala/collection/Iterator.html).| | **Maps:** | | | `xs map f` |The collection obtained from applying the function f to every element in `xs`.| @@ -107,8 +111,8 @@ f가 내놓는 결과값은 `foreach`가 무시한다. | `xs.max` |The maximum of the ordered element values of collection `xs`.| | **Strings:** | | | `xs addString (b, start, sep, end)`|Adds a string to `StringBuilder` `b` that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.| -| `xs mkString (start, sep, end)`|Converts the collection to a string that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.| -| `xs.stringPrefix` |The collection name at the beginning of the string returned from `xs.toString`.| -| **Views:** | | -| `xs.view` |Produces a view over `xs`.| -| `xs view (from, to)` |Produces a view that represents the elements in some index range of `xs`.| +| `xs mkString (start, sep, end)`|컬렉션 `xs`의 모든 원소를 `sep`로 구분해 문자열 `start`와 `end` 사이에 넣는다. `start`, `sep`, `end`를 지정하지 않으면 .| +| `xs.stringPrefix` |`xs.toString`이 반환하는 문자열의 맨 앞에 표시될 컬렉션 이름.| +| **뷰:** | | +| `xs.view` |`xs`에 대한 뷰를 만든다.| +| `xs view (from, to)` |`xs`에 대해 첨자 범위에 속하는 원소에 대한 뷰를 만든다.| From 21179e1bb71cc6616f0d1533e74318f713ea3338 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 04:46:08 +1000 Subject: [PATCH 07/17] =?UTF-8?q?trait-traversable.md=20=EC=9D=BC=EC=B0=A8?= =?UTF-8?q?=20=EB=B2=88=EC=97=AD=20=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/trait-traversable.md | 132 +++++++++--------- 1 file changed, 67 insertions(+), 65 deletions(-) diff --git a/ko/overviews/collections/trait-traversable.md b/ko/overviews/collections/trait-traversable.md index aaf217e9be..a387c1718d 100644 --- a/ko/overviews/collections/trait-traversable.md +++ b/ko/overviews/collections/trait-traversable.md @@ -34,9 +34,9 @@ f가 내놓는 결과값은 `foreach`가 무시한다. 무한한 순회가능한 컬렉션의 예를 들자면 자연수의 스트림 `Stream.from(0)`이 있다. 메소드 `hasDefiniteSize`는 컬렉션이 무한 컬렉션일 가능성이 있는지를 알려준다. `hasDefiniteSize`가 참을 반환하면 컬렉션이 유한하다는 것이 확실하다. 하지만, 컬렉션이 내부 원소를 아직 완전히 계산해 채우지 않은 경우에는 거짓을 반환하기 때문에, 거짓을 반환한다 해도 유한할 수도 있고 무한할 수도 있다. * **원소 가져오기** 연산 `head`, `last`, `headOption`, `lastOption`, `find`등은 컬렉션의 첫 원소나 마지막 원소를 선택하거나, 조건을 만족하는 첫 원소를 선택한다. 하지만 모든 컬렉션에서 "첫번째"나 "마지막"의 의미가 잘 정의되어 있는 것은 아니라는 점에 유의하라. 예를 들어 해시 집합은 해시값에 따라 원소를 저장하는데, 이 해시값은 매 실행시마다 변할 수 있다. 이런 경우 해시 집합의 "첫번째" 원소는 프로그램이 실행될 때마다 바뀔 수 있다. 어떤 컬렉션이 항상 같은 순서로 원소를 표시한다면 이를 _순서있다_ 고 한다. 대부분의 컬렉션은 순서가 있으나, 일부(_e.g._ 해시 집합)는 그렇지 않다 -- 이들은 순서를 포기하는 대신 효율을 택한 것이다. 동일한 테스트를 반복하거나, 디버깅을 할 때 때로 순서가 꼭 필요하다. 이 때문에 모든 스칼라 컬렉션 타입에는 순서가 있는 대체물이 반드시 존재한다. 예를 들어 `HashSet`에 순서가 부여된 것은 `LinkedHashSet`이다. -* **부분 컬렉션 가져오기** 연산에는 `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter` 등이 있다. 이들은 모두 어떤 첨자 범위나 술어 함수에 의해 식별되는 부분 컬렉션을 반환한다. +* **부분 컬렉션**을 가져오는 연산에는 `tail`, `init`, `slice`, `take`, `drop`, `takeWhile`, `dropWhile`, `filter`, `filterNot`, `withFilter` 등이 있다. 이들은 모두 어떤 첨자 범위나 술어 함수(predicate, 참-거짓을 반환하는 함수)에 의해 식별되는 부분 컬렉션을 반환한다. * **분할** 연산인 `splitAt`, `span`, `partition`, `groupBy` 등은 대상 컬렉션의 원소를 구분해서 여러 부분 컬렉션으로 나눈다. -* **원소 테스트** 연산 `exists`, `forall`, `count`는 주어진 술어 함수를 가지고 컬렉션 원소들을 검사한다. +* **원소 검사** 연산 `exists`, `forall`, `count`는 주어진 술어 함수를 가지고 컬렉션 원소들을 검사한다. * **폴드** 연산 `foldLeft`, `foldRight`, `/:`, `:\`, `reduceLeft`, `reduceRight`는 인접한 두 원소에 대해 이항 연산자(binary operator)를 반복적용한다. * **특정 폴드** `sum`, `product`, `min`, `max`는 특정 타입(비교가능하거나 수)의 컬렉션에만 작용한다. * **문자열** 연산 `mkString`, `addString`, `stringPrefix`는 컬렉션을 문자열로 바꾸는 여러가지 방법을 제공한다. @@ -49,70 +49,72 @@ f가 내놓는 결과값은 `foreach`가 무시한다. | **추상 메소드:** | | | `xs foreach f` |함수 `f`를 `xs`의 모든 원소에 적용한다.| | **병합:** | | -| `xs ++ ys` |A collection consisting of the elements of both `xs` and `ys`. `ys` is a [TraversableOnce](http://www.scala-lang.org/api/current/scala/collection/TraversableOnce.html) collection, i.e., either a [Traversable](http://www.scala-lang.org/api/current/scala/collection/Traversable.html) or an [Iterator](http://www.scala-lang.org/api/current/scala/collection/Iterator.html).| -| **Maps:** | | -| `xs map f` |The collection obtained from applying the function f to every element in `xs`.| -| `xs flatMap f` |The collection obtained from applying the collection-valued function `f` to every element in `xs` and concatenating the results.| -| `xs collect f` |The collection obtained from applying the partial function `f` to every element in `xs` for which it is defined and collecting the results.| -| **Conversions:** | | -| `xs.toArray` |Converts the collection to an array. | -| `xs.toList` |Converts the collection to a list. | -| `xs.toIterable` |Converts the collection to an iterable. | -| `xs.toSeq` |Converts the collection to a sequence. | -| `xs.toIndexedSeq` |Converts the collection to an indexed sequence. | -| `xs.toStream` |Converts the collection to a lazily computed stream.| -| `xs.toSet` |Converts the collection to a set. | -| `xs.toMap` |Converts the collection of key/value pairs to a map. If the collection does not have pairs as elements, calling this operation results in a static type error.| +| `xs ++ ys` |`xs`와 `ys`의 모든 원소들로 이루어진 컬렉션. `ys`는 [1회 순회가능(TraversableOnce)](http://www.scala-lang.org/api/current/scala/collection/TraversableOnce.html) 컬렉션이다. 즉, [순회가능(Traversable)](http://www.scala-lang.org/api/current/scala/collection/Traversable.html)이거나 [반복자(Iterator)](http://www.scala-lang.org/api/current/scala/collection/Iterator.html)여야 한다.| +| **맵:** | | +| `xs map f` |함수 `f`를 `xs`의 모든 원소에 적용해 반환된 결과로 이루어진 컬렉션을 반환한다.| +| `xs flatMap f` |결과값이 컬렉션인 함수 `f`를 `xs`의 모든 원소에 적용해 반환된 결과를 차례로 이어붙여서 이루어진 컬렉션을 반환한다.| +| `xs collect f` |부분함수(partial function) `f`를 모든 `xs`에 호출해서 결과값이 정의되어 있는 경우에 대해서만 그 값들을 모아서 이루어진 컬렉션을 반환한다.| +| **변환:** | | +| `xs.toArray` |컬렉션을 배열(Array)로 변환한다.| +| `xs.toList` |컬렉션을 리스트(List)로 변환한다.| +| `xs.toIterable` |컬렉션을 반복가능객체(Iterable)로 변환한다.| +| `xs.toSeq` |컬렉션을 순서열(Seq)로 변환한다.| +| `xs.toIndexedSeq` |컬렉션을 첨자가 있는 순서열(IndexedSeq)로 변환한다.| +| `xs.toStream` |컬렉션을 스트림(Stream)으로 변환한다.| +| `xs.toSet` |컬렉션을 집합(Set)으로 변환한다.| +| `xs.toMap` |컬렉션을 키/값 쌍의 맵으로 변환한다. 컬렉션의 원소가 튜플이 아니라면 이 메소드 호출은 컴파일시 타입 오류가 난다.| | **Copying:** | | -| `xs copyToBuffer buf` |Copies all elements of the collection to buffer `buf`.| -| `xs copyToArray(arr, s, n)`|Copies at most `n` elements of the collection to array `arr` starting at index `s`. The last two arguments are optional.| -| **Size info:** | | -| `xs.isEmpty` |Tests whether the collection is empty. | -| `xs.nonEmpty` |Tests whether the collection contains elements. | -| `xs.size` |The number of elements in the collection. | -| `xs.hasDefiniteSize` |True if `xs` is known to have finite size. | -| **Element Retrieval:** | | -| `xs.head` |The first element of the collection (or, some element, if no order is defined).| -| `xs.headOption` |The first element of `xs` in an option value, or None if `xs` is empty.| -| `xs.last` |The last element of the collection (or, some element, if no order is defined).| -| `xs.lastOption` |The last element of `xs` in an option value, or None if `xs` is empty.| -| `xs find p` |An option containing the first element in `xs` that satisfies `p`, or `None` is no element qualifies.| -| **Subcollections:** | | -| `xs.tail` |The rest of the collection except `xs.head`. | -| `xs.init` |The rest of the collection except `xs.last`. | -| `xs slice (from, to)` |A collection consisting of elements in some index range of `xs` (from `from` up to, and excluding `to`).| -| `xs take n` |A collection consisting of the first `n` elements of `xs` (or, some arbitrary `n` elements, if no order is defined).| -| `xs drop n` |The rest of the collection except `xs take n`.| -| `xs takeWhile p` |The longest prefix of elements in the collection that all satisfy `p`.| -| `xs dropWhile p` |The collection without the longest prefix of elements that all satisfy `p`.| -| `xs filter p` |The collection consisting of those elements of xs that satisfy the predicate `p`.| -| `xs withFilter p` |A non-strict filter of this collection. Subsequent calls to `map`, `flatMap`, `foreach`, and `withFilter` will only apply to those elements of `xs` for which the condition `p` is true.| -| `xs filterNot p` |The collection consisting of those elements of `xs` that do not satisfy the predicate `p`.| -| **Subdivisions:** | | -| `xs splitAt n` |Split `xs` at a position, giving the pair of collections `(xs take n, xs drop n)`.| -| `xs span p` |Split `xs` according to a predicate, giving the pair of collections `(xs takeWhile p, xs.dropWhile p)`.| -| `xs partition p` |Split `xs` into a pair of two collections; one with elements that satisfy the predicate `p`, the other with elements that do not, giving the pair of collections `(xs filter p, xs.filterNot p)`| -| `xs groupBy f` |Partition `xs` into a map of collections according to a discriminator function `f`.| -| **Element Conditions:** | | -| `xs forall p` |A boolean indicating whether the predicate `p` holds for all elements of `xs`.| -| `xs exists p` |A boolean indicating whether the predicate `p` holds for some element in `xs`.| -| `xs count p` |The number of elements in `xs` that satisfy the predicate `p`.| -| **Folds:** | | -| `(z /: xs)(op)` |Apply binary operation `op` between successive elements of `xs`, going left to right and starting with `z`.| -| `(xs :\ z)(op)` |Apply binary operation `op` between successive elements of `xs`, going right to left and starting with `z`.| -| `xs.foldLeft(z)(op)` |Same as `(z /: xs)(op)`.| -| `xs.foldRight(z)(op)` |Same as `(xs :\ z)(op)`.| -| `xs reduceLeft op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going left to right.| -| `xs reduceRight op` |Apply binary operation `op` between successive elements of non-empty collection `xs`, going right to left.| -| **Specific Folds:** | | -| `xs.sum` |The sum of the numeric element values of collection `xs`.| -| `xs.product` |The product of the numeric element values of collection `xs`.| -| `xs.min` |The minimum of the ordered element values of collection `xs`.| -| `xs.max` |The maximum of the ordered element values of collection `xs`.| -| **Strings:** | | -| `xs addString (b, start, sep, end)`|Adds a string to `StringBuilder` `b` that shows all elements of `xs` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional.| -| `xs mkString (start, sep, end)`|컬렉션 `xs`의 모든 원소를 `sep`로 구분해 문자열 `start`와 `end` 사이에 넣는다. `start`, `sep`, `end`를 지정하지 않으면 .| -| `xs.stringPrefix` |`xs.toString`이 반환하는 문자열의 맨 앞에 표시될 컬렉션 이름.| +| `xs copyToBuffer buf` |컬렉션의 모든 원소를 버퍼 `buf`에 복사한다.| +| `xs copyToArray(arr, s, n)`|첨자 `s`부터 시작해 최대 `n`개의 원소를 배열 `arr`에 복사한다. 마지막 두 매개변수는 생략할 수 있다.| +| **크기 정보:** | | +| `xs.isEmpty` |컬렉션이 비어있다면 참을 반환한다.| +| `xs.nonEmpty` |컬렉션에 원소가 하나라도 있다면 참을 반환한다.| +| `xs.size` |컬렉션의 원소의 갯수를 반환한다.| +| `xs.hasDefiniteSize` |`xs`가 유한한 크기를 가졌는지 알려져 있다면 참을 반환한다.| +| **원소 가져오기:** | | +| `xs.head` |컬렉션의 첫 원소(순서가 없는 컬렉션이라면 임의의 원소)를 반환한다.| +| `xs.headOption` |`xs`가 비어있다면 None, 그렇지 않다면 첫 원소를 Option에 담아서 반환한다.| +| `xs.last` |컬렉션의 마지막 원소(순서가 없는 컬렉션이라면 임의의 원소)를 반환한다.| +| `xs.lastOption` |`xs`가 비어있다면 None, 그렇지 않다면 마지막 원소를 Option에 담아서 반환한다.| +| `xs find p` |`xs`에서 `p`를 만족하는 첫번째 원소를 Option에 담아 반환한다. 만족하는 원소가 없다면 None을 반환한다.| +| **부분 컬렉션:** | | +| `xs.tail` |`xs.head`를 제외한 나머지 컬렉션이다.| +| `xs.init` |`xs.last`를 제외한 나머지 컬렉션이다.| +| `xs slice (from, to)` |컬렉션 `xs`에서 첨자 범위에 속하는 원소들(`from`부터 시작해서 `to`까지. 단, `from`에 있는 원소는 포함하고, `to`에 있는 원소는 포함하지 않음)로 이루어진 컬렉션을 반환한다.| +| `xs take n` |컬렉션 `xs`에서 앞에서부터 `n`개의 원소로 구성된 컬렉션(만약 순서가 없는 컬렉션이라면 임의의 `n`개의 원소가 선택된다)이다.| +| `xs drop n` |컬렉션에서 `xs take n`하고 난 나머지 컬렉션을 반환한다.| +| `xs takeWhile p` |컬렉션 `xs`의 맨 앞에서부터 술어 `p`를 만족하는 동안 원소를 수집해 만들어진 컬렉션. `p`를 만족하지 않는 첫 원소에서 수집은 끝난다. 따라서, 만약 `xs`의 첫 원소가 `p`를 만족하지 않으면 빈 컬렉션을 반환한다.| +| `xs dropWhile p` |컬렉션 `xs`의 맨 앞에서부터 따져서 술어 `p`를 최초로 만족하는 원소로부터 `xs`의 마지막 원소까지로 이루어진 컬렉션이다.| +| `xs filter p` |`xs`의 원소 중 술어 `p`를 만족하는 원소로 이루어진 컬렉션이다.| +| `xs withFilter p` |컬렉션에 필요시 계산하는 필터를 추가한다. 이 결과 컬렉션에 `map`, `flatMap`, `foreach`, `withFilter` 등이 호출되면 `xs` 중에 술어 `p`를 만족하는 원소에 대해서만 처리가 이루어진다.| +| `xs filterNot p` |`xs`의 원소 중 술어 `p`를 만족하지 않는 원소로 이루어진 컬렉션이다.| +| **분할:** | +| `xs splitAt n` |`n`위치를 기준으로 `xs`를 둘로 분할한다. `(xs take n, xs drop n)` 쌍과 동일한 컬렉션 쌍을 반환한다.| +| `xs span p` |`xs`를 술어 `p`를 가지고 둘로 분할하되, `(xs takeWhile p, xs.dropWhile p)`과 같은 컬렉션 쌍을 반환한다.| +| `xs partition p` |`xs`를 술어 `p`를 만족하는 원소들과 만족하지 않는 원소의 두 컬렉션으로 분할한 튜플을 반환한다. `(xs filter p, xs.filterNot p)`과 같은 결과를 반환한다.| +| `xs groupBy f` |`xs`를 분류 함수 `f`에 따르는 컬렉션의 맵으로 분할한다.| +| **원소 검사:** | | +| `xs forall p` |술어 `P`가 `xs`의 모든 원소에 대해 성립하는지 여부를 반환한다.| +| `xs exists p` |술어 `P`를 만족하는 원소가 `xs`에 있는지 여부를 반환한다.| +| `xs count p` |`xs`에서 술어 `P`를 만족하는 원소의 갯수를 반환한다.| +| **폴드:** | | +| `(z /: xs)(op)` |이항 연산 `op`를 `xs`의 인접 원소에 대해 `z`부터 시작해 왼쪽부터 오른쪽으로 차례로 적용한다.| +| `(xs :\ z)(op)` |이항 연산 `op`를 `xs`의 인접 원소에 대해 `z`부터 시작해 오른쪽부터 왼쪽으로 차례로 적용한다.| +| `xs.foldLeft(z)(op)` |`(z /: xs)(op)`과 같다.| +| `xs.foldRight(z)(op)` |`(xs :\ z)(op)`과 같다.| +| `xs reduceLeft op` |이항 연산 `op`를 비어있지 않은 `xs`의 인접 원소에 대해 왼쪽부터 오른쪽으로 차례로 적용한다.| +| `xs reduceRight op` |이항 연산 `op`를 비어있지 않은 `xs`의 인접 원소에 대해 오른쪽부터 왼쪽으로 차례로 적용한다.| +| **특정 폴드:** | | +| `xs.sum` |컬렉션 `xs`의 모든 수 원소를 곱한 값이다.| +| `xs.product` |컬렉션 `xs`의 모든 수 원소를 곱한 값이다.| +| `xs.min` |순서가 있는 컬렉션 `xs`에서 가장 작은 원소이다.| +| `xs.max` |순서가 있는 컬렉션 `xs`에서 가장 큰 원소이다.| +| **문자열:** | | +| `xs addString (b, start, sep, end)`|`StringBuilder` `b`에 `xs`의 모든 원소를 `sep`으로 구분해 `start`와 `end` 사이에 나열한 문자열을 추가한다. `start`, `sep`, `end`는 생략 가능하다.| +| `xs mkString (start, sep, end)`|컬렉션 `xs`의 모든 원소를 `sep`로 구분해 문자열 `start`와 `end` 사이에 넣는다. `start`, `sep`, `end`는 생략 가능하다.| +| `xs.stringPrefix` |`xs.toString`이 반환하는 문자열의 맨 앞에 표시될 컬렉션 이름이다.| | **뷰:** | | | `xs.view` |`xs`에 대한 뷰를 만든다.| | `xs view (from, to)` |`xs`에 대해 첨자 범위에 속하는 원소에 대한 뷰를 만든다.| + +번역: 오현석(enshahar@gmail.com) From 94ed496df79eb286a4d34ec56de87a2156814cc6 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 05:50:06 +1000 Subject: [PATCH 08/17] =?UTF-8?q?trait-iterable=20=EC=B4=88=EB=B2=8C=20?= =?UTF-8?q?=EB=B2=88=EC=97=AD?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/trait-iterable.md | 67 ++++++++++++++++++++++ overviews/collections/trait-iterable.md | 2 +- 2 files changed, 68 insertions(+), 1 deletion(-) create mode 100644 ko/overviews/collections/trait-iterable.md diff --git a/ko/overviews/collections/trait-iterable.md b/ko/overviews/collections/trait-iterable.md new file mode 100644 index 0000000000..1122bb9d79 --- /dev/null +++ b/ko/overviews/collections/trait-iterable.md @@ -0,0 +1,67 @@ +--- +layout: overview-large +title: 반복가능(Iterable) 트레잇 + +disqus: true + +partof: collections +num: 4 +language: ko +--- + +컬렉션 계층 구조의 맨 위에서 두번째에 있는 것이 `Iterable`(반복가능)이다. 이 트레잇에 있는 모든 메소드는 추상 메소드 `iterator`를 기반으로 정의되어 있다. 이 추상 메소드는 컬렉션의 원소를 하나씩 내어 놓는다. 트레잇 `Traversable`의 `foreach`는 `Iterable`에서 `iterator`를 기반으로 정의되어 있다. 다음은 실제 구현이다. + + def foreach[U](f: Elem => U): Unit = { + val it = iterator + while (it.hasNext) f(it.next()) + } + +`Iterable`의 하위 클래스 중 상당수는 이 `foreach` 표준 구현을 재정의(override)하고 있다. 왜냐하면 더 효율적인 구현이 가능하기 때문이다. `foreach`가 `Traversable`의 모든 메소드 구현에 사용됨을 기억하라. 따라서, 성능을 진지하게 고려해야 한다. + +`Iterable`에는 반복자를 반환하는 메소드가 두 개 더 있다. 이들은 각각 `grouped`와 `sliding`이다. 그러나 이 반복자들은 원래의 컬렉션의 한 원소만을 반환하는 것이 아니고, 전체 원소의 부분적인 순서열을 반환한다. 각 메소드는 이런 부분 순서열의 최대 크기를 인자로 받는다. `grouped` 메소드는 원소를 일정한 "덩어리(chunked)" 단위로 반환하는 반면, `sliding`은 원소에 대한 "미닫이 창(sliding window)"을 반환한다. 아래 REPL 수행 예를 보면 이 둘 사이의 차이를 명확히 알 수 있을 것이다. + + scala> val xs = List(1, 2, 3, 4, 5) + xs: List[Int] = List(1, 2, 3, 4, 5) + scala> val git = xs grouped 3 + git: Iterator[List[Int]] = non-empty iterator + scala> git.next() + res3: List[Int] = List(1, 2, 3) + scala> git.next() + res4: List[Int] = List(4, 5) + scala> val sit = xs sliding 3 + sit: Iterator[List[Int]] = non-empty iterator + scala> sit.next() + res5: List[Int] = List(1, 2, 3) + scala> sit.next() + res6: List[Int] = List(2, 3, 4) + scala> sit.next() + res7: List[Int] = List(3, 4, 5) + +`Traversable` 트레잇의 메소드 중 이터레이터가 있는 경우에만 효율적으로 구현할 수 있는 메소드 몇 가지를 `Iterable` 트레잇에서 재정의하고 있다. 다음 표에서 이를 요약하였다. + +### Iterable 트레잇의 연산들 ### + +| 사용법 | 하는일 | +| ------ | ------ | +| **추상 메소드:** | | +| `xs.iterator` |`iterator`는 `xs`의 모든 원소를 `foreach`가 순회하는 순서대로 하나씩 제공하는 반복자이다.| +| **다른 반복자:** | | +| `xs grouped size` |고정된 크기의 "덩어리"를 컬렉션에서 내어놓는 반복자이다.| +| `xs sliding size` |고정된 크기의 미닫이 창을 내어놓는 반복자이다.| +| **부분 컬렉션:** | | +| `xs takeRight n` |`xs`의 마지막 `n`개의 원소로 이루어진 컬렉션을 반환한다(순서가 없는 컬렉션이라면 임의의 `n`개를 반환한다).| +| `xs dropRight n` |`xs takeRight n`의 결과를 제외한 나머지 컬렉션을 반환한다.| +| **묶기(zip):** | | +| `xs zip ys` |`xs`와 `ys`에서 같은 위치에 있는 원소를 각각 가져와 만든 튜플로 이루어진 컬렉션을 반환한다. (길이가 다르다면 짧은쪽 리스트의 원소 갯수 만큼만 반환한다.) | +| `xs zipAll (ys, x, y)` |`zip`과 같지만, 길이가 다른 경우 `x`나 `y`를 더 짧은쪽 리스트의 원소가 모자란 경우 대신 사용한다.| +| `xs.zipWithIndex` |`xs`의 원소와 그 위치를 나타내는 첨자를 튜플로 만든 컬렉션을 반환한다.| +| **비교:** | | +| `xs sameElements ys` |`xs`와 `ys`가 같은 순서로 같은 원소를 포함하고 있는지 비교한다.| + +상속 계층에서 Iterable의 하위에는 다음 세 트레잇이 있다. [순서열(Seq)](http://www.scala-lang.org/docu/files/collections-api/collections_5.html), [집합(Set)](http://www.scala-lang.org/docu/files/collections-api/collections_7.html), [맵(Map)](http://www.scala-lang.org/docu/files/collections-api/collections_10.html)가 그것이다. 이 세 트레잇의 공통점은 모두 다 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html) 트레잇의 `apply`와 `isDefinedAt` 메소드를 정의하고 있다는 것이다. 하지만, 각 트레잇이 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html)를 구현한 방법은 각각 다르다. + +순서열에서 `apply`는 위치에 따라 첨자를 부여한다. 이는 첫번째 원소의 첨자 `0`부터 시작한다. 따라서 `Seq(1, 2, 3)(1)`은 `2`를 반환한다. 집합의 경우 `apply`는 포함관계 검사이다. 예를 들어 `Set('a', 'b', 'c')('b')`은 `true`를, `Set()('a')`는 `false`를 반환한다. 마지막으로 맵의 경우 `apply`는 선택(검색)이다. 예를 들어 `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')`의 결과는 `10`이다. + +다음 글에서는 위 세 컬렉션을 더 자세히 살펴볼 것이다. + +번역: 오현석(enshahar@gmail.com) diff --git a/overviews/collections/trait-iterable.md b/overviews/collections/trait-iterable.md index 0fb7ab53b2..f89eca4b75 100644 --- a/overviews/collections/trait-iterable.md +++ b/overviews/collections/trait-iterable.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 4 -languages: [ja] +languages: [ja, ko] --- The next trait from the top in the collections hierarchy is `Iterable`. All methods in this trait are defined in terms of an an abstract method, `iterator`, which yields the collection's elements one by one. The `foreach` method from trait `Traversable` is implemented in `Iterable` in terms of `iterator`. Here is the actual implementation: From 71134de3164f24bfd865e4012f994fc65314c202 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 13:38:20 +1000 Subject: [PATCH 09/17] =?UTF-8?q?=EC=96=B8=EC=96=B4=20=EC=95=84=EC=9D=B4?= =?UTF-8?q?=EC=BD=98=20=EC=83=9D=EC=84=B1=EC=9D=84=20=EC=9C=84=ED=95=B4=20?= =?UTF-8?q?=EC=98=81=EB=AC=B8=ED=8C=8C=EC=9D=BC=EC=9D=84=20=EC=9D=BC?= =?UTF-8?q?=EB=8B=A8=20=EB=8B=A4=20=ED=95=9C=EA=B8=80=ED=8C=8C=EC=9D=BC?= =?UTF-8?q?=EB=A1=9C=20=EB=B3=B5=EC=82=AC?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/arrays.md | 118 ++++++++++ .../concrete-immutable-collection-classes.md | 216 ++++++++++++++++++ .../concrete-mutable-collection-classes.md | 182 +++++++++++++++ ...ions-between-java-and-scala-collections.md | 58 +++++ .../creating-collections-from-scratch.md | 58 +++++ ko/overviews/collections/equality.md | 31 +++ ko/overviews/collections/iterators.md | 176 ++++++++++++++ ko/overviews/collections/maps.md | 164 +++++++++++++ .../collections/migrating-from-scala-27.md | 45 ++++ ko/overviews/collections/overview.md | 17 +- .../performance-characteristics.md | 85 +++++++ ko/overviews/collections/seqs.md | 101 ++++++++ ko/overviews/collections/sets.md | 150 ++++++++++++ ko/overviews/collections/strings.md | 27 +++ ko/overviews/collections/trait-traversable.md | 6 +- ko/overviews/collections/views.md | 129 +++++++++++ ko/overviews/core/collections.md | 2 +- overviews/collections/arrays.md | 2 +- .../concrete-immutable-collection-classes.md | 2 +- .../concrete-mutable-collection-classes.md | 2 +- ...ions-between-java-and-scala-collections.md | 2 +- .../creating-collections-from-scratch.md | 4 +- overviews/collections/equality.md | 2 +- overviews/collections/introduction.md | 2 +- overviews/collections/iterators.md | 2 +- overviews/collections/maps.md | 2 +- .../collections/migrating-from-scala-27.md | 2 +- overviews/collections/overview.md | 2 +- .../performance-characteristics.md | 2 +- overviews/collections/seqs.md | 2 +- overviews/collections/sets.md | 2 +- overviews/collections/strings.md | 4 +- overviews/collections/views.md | 2 +- 33 files changed, 1569 insertions(+), 32 deletions(-) create mode 100644 ko/overviews/collections/arrays.md create mode 100644 ko/overviews/collections/concrete-immutable-collection-classes.md create mode 100644 ko/overviews/collections/concrete-mutable-collection-classes.md create mode 100644 ko/overviews/collections/conversions-between-java-and-scala-collections.md create mode 100644 ko/overviews/collections/creating-collections-from-scratch.md create mode 100644 ko/overviews/collections/equality.md create mode 100644 ko/overviews/collections/iterators.md create mode 100644 ko/overviews/collections/maps.md create mode 100644 ko/overviews/collections/migrating-from-scala-27.md mode change 100755 => 100644 ko/overviews/collections/overview.md create mode 100644 ko/overviews/collections/performance-characteristics.md create mode 100644 ko/overviews/collections/seqs.md create mode 100644 ko/overviews/collections/sets.md create mode 100644 ko/overviews/collections/strings.md create mode 100644 ko/overviews/collections/views.md diff --git a/ko/overviews/collections/arrays.md b/ko/overviews/collections/arrays.md new file mode 100644 index 0000000000..17489da133 --- /dev/null +++ b/ko/overviews/collections/arrays.md @@ -0,0 +1,118 @@ +--- +layout: overview-large +title: Arrays + +disqus: true + +partof: collections +num: 10 +language: ko +--- + +[Array](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) is a special kind of collection in Scala. On the one hand, Scala arrays correspond one-to-one to Java arrays. That is, a Scala array `Array[Int]` is represented as a Java `int[]`, an `Array[Double]` is represented as a Java `double[]` and a `Array[String]` is represented as a `Java String[]`. But at the same time, Scala arrays offer much more than their Java analogues. First, Scala arrays can be _generic_. That is, you can have an `Array[T]`, where `T` is a type parameter or abstract type. Second, Scala arrays are compatible with Scala sequences - you can pass an `Array[T]` where a `Seq[T]` is required. Finally, Scala arrays also support all sequence operations. Here's an example of this in action: + + scala> val a1 = Array(1, 2, 3) + a1: Array[Int] = Array(1, 2, 3) + scala> val a2 = a1 map (_ * 3) + a2: Array[Int] = Array(3, 6, 9) + scala> val a3 = a2 filter (_ % 2 != 0) + a3: Array[Int] = Array(3, 9) + scala> a3.reverse + res1: Array[Int] = Array(9, 3) + +Given that Scala arrays are represented just like Java arrays, how can these additional features be supported in Scala? In fact, the answer to this question differs between Scala 2.8 and earlier versions. Previously, the Scala compiler somewhat "magically" wrapped and unwrapped arrays to and from `Seq` objects when required in a process called boxing and unboxing. The details of this were quite complicated, in particular when one created a new array of generic type `Array[T]`. There were some puzzling corner cases and the performance of array operations was not all that predictable. + +The Scala 2.8 design is much simpler. Almost all compiler magic is gone. Instead the Scala 2.8 array implementation makes systematic use of implicit conversions. In Scala 2.8 an array does not pretend to _be_ a sequence. It can't really be that because the data type representation of a native array is not a subtype of `Seq`. Instead there is an implicit "wrapping" conversion between arrays and instances of class `scala.collection.mutable.WrappedArray`, which is a subclass of `Seq`. Here you see it in action: + + scala> val seq: Seq[Int] = a1 + seq: Seq[Int] = WrappedArray(1, 2, 3) + scala> val a4: Array[Int] = s.toArray + a4: Array[Int] = Array(1, 2, 3) + scala> a1 eq a4 + res2: Boolean = true + +The interaction above demonstrates that arrays are compatible with sequences, because there's an implicit conversion from arrays to `WrappedArray`s. To go the other way, from a `WrappedArray` to an `Array`, you can use the `toArray` method defined in `Traversable`. The last REPL line above shows that wrapping and then unwrapping with `toArray` gives the same array you started with. + +There is yet another implicit conversion that gets applied to arrays. This conversion simply "adds" all sequence methods to arrays but does not turn the array itself into a sequence. "Adding" means that the array is wrapped in another object of type `ArrayOps` which supports all sequence methods. Typically, this `ArrayOps` object is short-lived; it will usually be inaccessible after the call to the sequence method and its storage can be recycled. Modern VMs often avoid creating this object entirely. + +The difference between the two implicit conversions on arrays is shown in the next REPL dialogue: + + scala> val seq: Seq[Int] = a1 + seq: Seq[Int] = WrappedArray(1, 2, 3) + scala> seq.reverse + res2: Seq[Int] = WrappedArray(3, 2, 1) + scala> val ops: collection.mutable.ArrayOps[Int] = a1 + ops: scala.collection.mutable.ArrayOps[Int] = [I(1, 2, 3) + scala> ops.reverse + res3: Array[Int] = Array(3, 2, 1) + +You see that calling reverse on `seq`, which is a `WrappedArray`, will give again a `WrappedArray`. That's logical, because wrapped arrays are `Seqs`, and calling reverse on any `Seq` will give again a `Seq`. On the other hand, calling reverse on the ops value of class `ArrayOps` will give an `Array`, not a `Seq`. + +The `ArrayOps` example above was quite artificial, intended only to show the difference to `WrappedArray`. Normally, you'd never define a value of class `ArrayOps`. You'd just call a `Seq` method on an array: + + scala> a1.reverse + res4: Array[Int] = Array(3, 2, 1) + +The `ArrayOps` object gets inserted automatically by the implicit conversion. So the line above is equivalent to + + scala> intArrayOps(a1).reverse + res5: Array[Int] = Array(3, 2, 1) + +where `intArrayOps` is the implicit conversion that was inserted previously. This raises the question how the compiler picked `intArrayOps` over the other implicit conversion to `WrappedArray` in the line above. After all, both conversions map an array to a type that supports a reverse method, which is what the input specified. The answer to that question is that the two implicit conversions are prioritized. The `ArrayOps` conversion has a higher priority than the `WrappedArray` conversion. The first is defined in the `Predef` object whereas the second is defined in a class `scala.LowPritoryImplicits`, which is inherited from `Predef`. Implicits in subclasses and subobjects take precedence over implicits in base classes. So if both conversions are applicable, the one in `Predef` is chosen. A very similar scheme works for strings. + +So now you know how arrays can be compatible with sequences and how they can support all sequence operations. What about genericity? In Java you cannot write a `T[]` where `T` is a type parameter. How then is Scala's `Array[T]` represented? In fact a generic array like `Array[T]` could be at run-time any of Java's eight primitive array types `byte[]`, `short[]`, `char[]`, `int[]`, `long[]`, `float[]`, `double[]`, `boolean[]`, or it could be an array of objects. The only common run-time type encompassing all of these types is `AnyRef` (or, equivalently `java.lang.Object`), so that's the type to which the Scala compiler maps `Array[T]`. At run-time, when an element of an array of type `Array[T]` is accessed or updated there is a sequence of type tests that determine the actual array type, followed by the correct array operation on the Java array. These type tests slow down array operations somewhat. You can expect accesses to generic arrays to be three to four times slower than accesses to primitive or object arrays. This means that if you need maximal performance, you should prefer concrete over generic arrays. Representing the generic array type is not enough, however, There must also be a way to create generic arrays. This is an even harder problem, which requires a little bit of help from you. To illustrate the problem, consider the following attempt to write a generic method that creates an array. + + // this is wrong! + def evenElems[T](xs: Vector[T]): Array[T] = { + val arr = new Array[T]((xs.length + 1) / 2) + for (i <- 0 until xs.length by 2) + arr(i / 2) = xs(i) + arr + } + +The `evenElems` method returns a new array that consist of all elements of the argument vector `xs` which are at even positions in the vector. The first line of the body of `evenElems` creates the result array, which has the same element type as the argument. So depending on the actual type parameter for `T`, this could be an `Array[Int]`, or an `Array[Boolean]`, or an array of some of the other primitive types in Java, or an array of some reference type. But these types have all different runtime representations, so how is the Scala runtime going to pick the correct one? In fact, it can't do that based on the information it is given, because the actual type that corresponds to the type parameter `T` is erased at runtime. That's why you will get the following error message if you compile the code above: + + error: cannot find class manifest for element type T + val arr = new Array[T]((arr.length + 1) / 2) + ^ +What's required here is that you help the compiler out by providing some runtime hint what the actual type parameter of `evenElems` is. This runtime hint takes the form of a class manifest of type `scala.reflect.ClassManifest`. A class manifest is a type descriptor object which describes what the top-level class of a type is. Alternatively to class manifests there are also full manifests of type `scala.reflect.Manifest`, which describe all aspects of a type. But for array creation, only class manifests are needed. + +The Scala compiler will construct class manifests automatically if you instruct it to do so. "Instructing" means that you demand a class manifest as an implicit parameter, like this: + + def evenElems[T](xs: Vector[T])(implicit m: ClassManifest[T]): Array[T] = ... + +Using an alternative and shorter syntax, you can also demand that the type comes with a class manifest by using a context bound. This means following the type with a colon and the class name `ClassManifest`, like this: + + // this works + def evenElems[T: ClassManifest](xs: Vector[T]): Array[T] = { + val arr = new Array[T]((xs.length + 1) / 2) + for (i <- 0 until xs.length by 2) + arr(i / 2) = xs(i) + arr + } + +The two revised versions of `evenElems` mean exactly the same. What happens in either case is that when the `Array[T]` is constructed, the compiler will look for a class manifest for the type parameter T, that is, it will look for an implicit value of type `ClassManifest[T]`. If such a value is found, the manifest is used to construct the right kind of array. Otherwise, you'll see an error message like the one above. + +Here is some REPL interaction that uses the `evenElems` method. + + scala> evenElems(Vector(1, 2, 3, 4, 5)) + res6: Array[Int] = Array(1, 3, 5) + scala> evenElems(Vector("this", "is", "a", "test", "run")) + res7: Array[java.lang.String] = Array(this, a, run) + +In both cases, the Scala compiler automatically constructed a class manifest for the element type (first, `Int`, then `String`) and passed it to the implicit parameter of the `evenElems` method. The compiler can do that for all concrete types, but not if the argument is itself another type parameter without its class manifest. For instance, the following fails: + + scala> def wrap[U](xs: Array[U]) = evenElems(xs) + :6: error: could not find implicit value for + evidence parameter of type ClassManifest[U] + def wrap[U](xs: Array[U]) = evenElems(xs) + ^ +What happened here is that the `evenElems` demands a class manifest for the type parameter `U`, but none was found. The solution in this case is, of course, to demand another implicit class manifest for `U`. So the following works: + + scala> def wrap[U: ClassManifest](xs: Array[U]) = evenElems(xs) + wrap: [U](xs: Array[U])(implicit evidence$1: ClassManifest[U])Array[U] + +This example also shows that the context bound in the definition of `U` is just a shorthand for an implicit parameter named here `evidence$1` of type `ClassManifest[U]`. + +In summary, generic array creation demands class manifests. So whenever creating an array of a type parameter `T`, you also need to provide an implicit class manifest for `T`. The easiest way to do this is to declare the type parameter with a `ClassManifest` context bound, as in `[T: ClassManifest]`. + diff --git a/ko/overviews/collections/concrete-immutable-collection-classes.md b/ko/overviews/collections/concrete-immutable-collection-classes.md new file mode 100644 index 0000000000..5d06c842b1 --- /dev/null +++ b/ko/overviews/collections/concrete-immutable-collection-classes.md @@ -0,0 +1,216 @@ +--- +layout: overview-large +title: Concrete Immutable Collection Classes + +disqus: true + +partof: collections +num: 8 +language: ko +--- + +Scala provides many concrete immutable collection classes for you to choose from. They differ in the traits they implement (maps, sets, sequences), whether they can be infinite, and the speed of various operations. Here are some of the most common immutable collection types used in Scala. + +## Lists + +A [List](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/List.html) is a finite immutable sequence. They provide constant-time access to their first element as well as the rest of the list, and they have a constant-time cons operation for adding a new element to the front of the list. Many other operations take linear time. + +Lists have always been the workhorse for Scala programming, so not much needs to be said about them here. The major change in 2.8 is that the `List` class together with its subclass `::` and its subobject `Nil` is now defined in package `scala.collection.immutable`, where it logically belongs. There are still aliases for `List`, `Nil`, and `::` in the `scala` package, so from a user perspective, lists can be accessed as before. + +Another change is that lists now integrate more closely into the collections framework, and are less of a special case than before. For instance all of the numerous methods that originally lived in the `List` companion object have been deprecated. They are replaced by the [uniform creation methods]({{ site.baseurl }}/overviews/collections/creating-collections-from-scratch.html) inherited by every collection. + +## Streams + +A [Stream](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Stream.html) is like a list except that its elements are computed lazily. Because of this, a stream can be infinitely long. Only those elements requested are computed. Otherwise, streams have the same performance characteristics as lists. + +Whereas lists are constructed with the `::` operator, streams are constructed with the similar-looking `#::`. Here is a simple example of a stream containing the integers 1, 2, and 3: + + scala> val str = 1 #:: 2 #:: 3 #:: Stream.empty + str: scala.collection.immutable.Stream[Int] = Stream(1, ?) + +The head of this stream is 1, and the tail of it has 2 and 3. The tail is not printed here, though, because it hasn't been computed yet! Streams are specified to compute lazily, and the `toString` method of a stream is careful not to force any extra evaluation. + +Below is a more complex example. It computes a stream 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. + + + scala> def fibFrom(a: Int, b: Int): Stream[Int] = a #:: fibFrom(b, a + b) + fibFrom: (a: Int,b: Int)Stream[Int] + +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: + + scala> val fibs = fibFrom(1, 1).take(7) + fibs: scala.collection.immutable.Stream[Int] = Stream(1, ?) + scala> fibs.toList + res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13) + +## Vectors + +Lists are very efficient when the algorithm processing them is careful to only process their heads. Accessing, adding, and removing the head of a list takes only constant time, whereas accessing or modifying elements later in the list takes time linear in the depth into the list. + +[Vector](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Vector.html) is a collection type (introduced in Scala 2.8) that addresses the inefficiency for random access on lists. Vectors allow accessing any element of the list in "effectively" constant time. It's a larger constant than for access to the head of a list or for reading an element of an array, but it's a constant nonetheless. As a result, algorithms using vectors do not have to be careful about accessing just the head of the sequence. They can access and modify elements at arbitrary locations, and thus they can be much more convenient to write. + +Vectors are built and modified just like any other sequence. + + 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 + +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). 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". + +Vectors are immutable, so you cannot change an element of a vector and still retain a new vector. However, with the `updated` method you can crate a new vector that differs from a given vector only in a single element: + + scala> val vec = Vector(1, 2, 3) + vec: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3) + scala> vec updated (2, 4) + res0: scala.collection.immutable.Vector[Int] = Vector(1, 2, 4) + scala> vec + res1: scala.collection.immutable.Vector[Int] = Vector(1, 2, 3) + +As the last line above shows, a call to `updated` has no effect on the original vector `vec`. Like selection, functional vector updates are also "effectively constant time". Updating an element in the middle of a vector can be done by copying the node that contains the element, and every node that points to it, starting from the root of the tree. This means that a functional update creates between one and five nodes that each contain up to 32 elements or subtrees. This is certainly more expensive than an in-place update in a mutable array, but still a lot cheaper than copying the whole vector. + +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: + + + scala> collection.immutable.IndexedSeq(1, 2, 3) + res2: scala.collection.immutable.IndexedSeq[Int] = Vector(1, 2, 3) + +## Immutable stacks + +If you need a last-in-first-out sequence, you can use a [Stack](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Stack.html). You push an element onto a stack with `push`, pop an element with `pop`, and peek at the top of the stack without removing it with `top`. All of these operations are constant time. + +Here are some simple operations performed on a stack: + + + scala> val stack = scala.collection.immutable.Stack.empty + stack: scala.collection.immutable.Stack[Nothing] = Stack() + scala> val hasOne = stack.push(1) + hasOne: scala.collection.immutable.Stack[Int] = Stack(1) + scala> stack + stack: scala.collection.immutable.Stack[Nothing] = Stack() + scala> hasOne.top + res20: Int = 1 + scala> hasOne.pop + res19: scala.collection.immutable.Stack[Int] = Stack() + +Immutable stacks are used rarely in Scala programs because their functionality is subsumed by lists: A `push` on an immutable stack is the same as a `::` on a list and a `pop` on a stack is the same a `tail` on a list. + +## Immutable Queues + +A [Queue](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Queue.html) is just like a stack except that it is first-in-first-out rather than last-in-first-out. + +Here's how you can create an empty immutable queue: + + scala> val empty = scala.collection.immutable.Queue[Int]() + empty: scala.collection.immutable.Queue[Int] = Queue() + +You can append an element to an immutable queue with `enqueue`: + + scala> val has1 = empty.enqueue(1) + has1: scala.collection.immutable.Queue[Int] = Queue(1) + +To append multiple elements to a queue, call `enqueue` with a collection as its argument: + + scala> val has123 = has1.enqueue(List(2, 3)) + has123: scala.collection.immutable.Queue[Int] + = Queue(1, 2, 3) + +To remove an element from the head of the queue, you use `dequeue`: + + scala> val (element, has23) = has123.dequeue + element: Int = 1 + has23: scala.collection.immutable.Queue[Int] = Queue(2, 3) + +Note that `dequeue` returns a pair consisting of the element removed and the rest of the queue. + +## Ranges + +A [Range](http://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`. + + scala> 1 to 3 + res2: scala.collection.immutable.Range.Inclusive + with scala.collection.immutable.Range.ByOne = Range(1, 2, 3) + scala> 5 to 14 by 3 + res3: scala.collection.immutable.Range = Range(5, 8, 11, 14) + +If you want to create a range that is exclusive of its upper limit, then use the convenience method `until` instead of `to`: + + scala> 1 until 3 + res2: scala.collection.immutable.Range.Inclusive + with scala.collection.immutable.Range.ByOne = Range(1, 2) + +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. + +## Hash Tries + +Hash tries are a standard way to implement immutable sets and maps efficiently. They are supported by class [immutable.HashMap](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/HashMap.html). Their representation is similar to vectors in that they are also trees where every node has 32 elements or 32 subtrees. But the selection of these keys is now done based on hash code. For instance, to find a given key in a map, one first takes the hash code of the key. Then, the lowest 5 bits of the hash code are used to select the first subtree, followed by the next 5 bits and so on. The selection stops once all elements stored in a node have hash codes that differ from each other in the bits that are selected up to this level. + +Hash tries strike a nice balance between reasonably fast lookups and reasonably efficient functional insertions (`+`) and deletions (`-`). That's why they underly Scala's default implementations of immutable maps and sets. In fact, Scala has a further optimization for immutable sets and maps that contain less than five elements. Sets and maps with one to four elements are stored as single objects that just contain the elements (or key/value pairs in the case of a map) as fields. The empty immutable set and the empty immutable map is in each case a single object - there's no need to duplicate storage for those because and empty immutable set or map will always stay empty. + +## Red-Black Trees + +Red-black trees are a form of balanced binary trees where some nodes are designated "red" and others designated "black." Like any balanced binary tree, operations on them reliably complete in time logarithmic to the size of the tree. + +Scala provides implementations of immutable sets and maps that use a red-black tree internally. Access them under the names [TreeSet](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeSet.html) and [TreeMap](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/TreeMap.html). + + + 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) + +Red black trees are the standard implementation of `SortedSet` in Scala, because they provide an efficient iterator that returns all elements in sorted order. + +## Immutable BitSets + +A [BitSet](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/BitSet.html) represents a collection of small integers as the bits of a larger integer. For example, the bit set containing 3, 2, and 0 would be represented as the integer 1101 in binary, which is 13 in decimal. + +Internally, bit sets use an array of 64-bit `Long`s. The first `Long` in the array is for integers 0 through 63, the second is for 64 through 127, and so on. Thus, bit sets are very compact so long as the largest integer in the set is less than a few hundred or so. + +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: + + 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 + +## List Maps + +A [ListMap](http://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 difference 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. + + 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" + + + + + + + + + + + + + + + + + + + + + + diff --git a/ko/overviews/collections/concrete-mutable-collection-classes.md b/ko/overviews/collections/concrete-mutable-collection-classes.md new file mode 100644 index 0000000000..32f8bb4331 --- /dev/null +++ b/ko/overviews/collections/concrete-mutable-collection-classes.md @@ -0,0 +1,182 @@ +--- +layout: overview-large +title: Concrete Mutable Collection Classes + +disqus: true + +partof: collections +num: 9 +language: ko +--- + +You've now seen the most commonly used immutable collection classes that Scala provides in its standard library. Take a look now at the mutable collection classes. + +## Array Buffers + +An [ArrayBuffer](http://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. + + 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) + +## List Buffers + +A [ListBuffer](http://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. + + 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 + res37: List[Int] = List(1, 10) + +## StringBuilders + +Just like an array buffer is useful for building arrays, and a list buffer is useful for building lists, a [StringBuilder](http://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: + + 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 + +## Linked Lists + +Linked lists are mutable sequences that consist of nodes which are linked with next pointers. They are supported by class [LinkedList](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/LinkedList.html). In most languages `null` would be picked as the empty linked list. That does not work for Scala collections, because even empty sequences must support all sequence methods. In particular `LinkedList.empty.isEmpty` should return `true` and not throw a `NullPointerException`. Empty linked lists are encoded instead in a special way: Their `next` field points back to the node itself. Like their immutable cousins, linked lists are best traversed sequentially. In addition linked lists make it easy to insert an element or linked list into another linked list. + +## Double Linked Lists + +Double linked lists are like single linked lists, except that they have besides `next` another mutable field `prev` that points to the element preceding the current node. The main benefit of that additional link is that it makes element removal very fast. Double linked lists are supported by class [DoubleLinkedList](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/DoubleLinkedList.html). + +## Mutable Lists + +A [MutableList](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/MutableList.html) consists of a single linked list together with a pointer that refers to the terminal empty node of that list. This makes list append a constant time operation because it avoids having to traverse the list in search for its terminal node. [MutableList](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/MutableList.html) is currently the standard implementation of [mutable.LinearSeq](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/LinearSeq.html) in Scala. + +## Queues + +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: + + 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) + +## Array Sequences + +Array sequences are mutable sequences of fixed size which store their elements internally in an `Array[Object]`. They are implemented in Scala by class [ArraySeq](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArraySeq.html). + +You would typically use an `ArraySeq` if you want an array for its performance characteristics, but you also want to create generic instances of the sequence where you do not know the type of the elements and you do not have a `ClassManifest` to provide it at run-time. These issues are explained in the section on [arrays]({{ site.baseurl }}/overviews/collections/arrays.html). + +## Stacks + +You saw immutable stacks earlier. There is also a mutable version, supported by class [mutable.Stack](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/Stack.html). It works exactly the same as the immutable version except that modifications happen in place. + + 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) + +## Array Stacks + +[ArrayStack](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/ArrayStack.html) is an alternative implementation of a mutable stack which is backed by an Array that gets re-sized as needed. It provides fast indexing and is generally slightly more efficient for most operations than a normal mutable stack. + +## Hash Tables + +A hash table stores its elements in an underlying array, placing each item at a position in the array determined by the hash code of that item. Adding an element to a hash table takes only constant time, so long as there isn't already another element in the array that has the same hash code. Hash tables are thus very fast so long as the objects placed in them have a good distribution of hash codes. As a result, the default mutable map and set types in Scala are based on hash tables. You can access them also directly under the names [mutable.HashSet](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/HashSet.html) and [mutable.HashMap](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/HashMap.html). + +Hash sets and maps are used just like any other set or map. Here are some simple examples: + + 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 + +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. + +## Weak Hash Maps + +A weak hash map is a special kind of hash map where the garbage collector does not follow links from the map to the keys stored in it. This means that a key and its associated value will disappear from the map if there is no other reference to that key. Weak hash maps are useful for tasks such as caching, where you want to re-use an expensive function's result if the function is called again on the same key. If keys and function results are stored in a regular hash map, the map could grow without bounds, and no key would ever become garbage. Using a weak hash map avoids this problem. As soon as a key object becomes unreachable, it's entry is removed from the weak hashmap. Weak hash maps in Scala are implemented by class [WeakHashMap](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/mutable/WeakHashMap.html) as a wrapper of an underlying Java implementation `java.util.WeakHashMap`. + +## Concurrent Maps + +A concurrent map can be accessed by several threads at once. In addition to the usual [Map](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Map.html) operations, it provides the following atomic operations: + +### Operations in class ConcurrentMap + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| `m putIfAbsent(k, v)` |Adds key/value binding `k -> m` unless `k` is already defined in `m` | +| `m remove (k, v)` |Removes entry for `k` if it is currently mapped to `v`. | +| `m replace (k, old, new)` |Replaces value associated with key `k` to `new`, if it was previously bound to `old`. | +| `m replace (k, v)` |Replaces value associated with key `k` to `v`, if it was previously bound to some value.| + +`ConcurrentMap` is a trait in the Scala collections library. Currently, its only implementation is Java's `java.util.concurrent.ConcurrentMap`, which can be converted automatically into a Scala map using the [standard Java/Scala collection conversions]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.html). + +## Mutable Bitsets + +A mutable bit of type [mutable.BitSet](http://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. + + 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) + + + + + + + + + + + + + + + + + + diff --git a/ko/overviews/collections/conversions-between-java-and-scala-collections.md b/ko/overviews/collections/conversions-between-java-and-scala-collections.md new file mode 100644 index 0000000000..0be674d3e2 --- /dev/null +++ b/ko/overviews/collections/conversions-between-java-and-scala-collections.md @@ -0,0 +1,58 @@ +--- +layout: overview-large +title: Conversions Between Java and Scala Collections + +disqus: true + +partof: collections +num: 17 +language: ko +--- + +Like Scala, Java also has a rich collections library. There are many similarities between the two. For instance, both libraries know iterators, iterables, sets, maps, and sequences. But there are also important differences. In particular, the Scala libraries put much more emphasis on immutable collections, and provide many more operations that transform a collection into a new one. + +Sometimes you might need to pass from one collection framework to the other. For instance, you might want to access to an existing Java collection, as if it was a Scala collection. Or you might want to pass one of Scala's collections to a Java method that expects its Java counterpart. It is quite easy to do this, because Scala offers implicit conversions between all the major collection types in the [JavaConversions](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/JavaConversions$.html) object. In particular, you will find bidirectional conversions between the following types. + + + Iterator <=> java.util.Iterator + Iterator <=> java.util.Enumeration + Iterable <=> java.lang.Iterable + Iterable <=> java.util.Collection + mutable.Buffer <=> java.util.List + mutable.Set <=> java.util.Set + mutable.Map <=> java.util.Map + mutable.ConcurrentMap <=> java.util.concurrent.ConcurrentMap + +To enable these conversions, simply import them from the [JavaConversions](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/JavaConversions$.html) object: + + scala> import collection.JavaConversions._ + import collection.JavaConversions._ + +You have now automatic conversions between Scala collections and their corresponding Java collections. + + scala> import collection.mutable._ + import collection.mutable._ + scala> val jul: java.util.List[Int] = ArrayBuffer(1, 2, 3) + jul: java.util.List[Int] = [1, 2, 3] + scala> val buf: Seq[Int] = jul + buf: scala.collection.mutable.Seq[Int] = ArrayBuffer(1, 2, 3) + scala> val m: java.util.Map[String, Int] = HashMap("abc" -> 1, "hello" -> 2) + m: java.util.Map[String,Int] = {hello=2, abc=1} + +Internally, these conversion work by setting up a "wrapper" object that forwards all operations to the underlying collection object. So collections are never copied when converting between Java and Scala. An interesting property is that if you do a round-trip conversion from, say a Java type to its corresponding Scala type, and back to the same Java type, you end up with the identical collection object you have started with. + +The are some other common Scala collections than can also be converted to Java types, but which to not have a corresponding conversion in the other sense. These are: + + Seq => java.util.List + mutable.Seq => java.utl.List + Set => java.util.Set + Map => java.util.Map + +Because Java does not distinguish between mutable and immutable collections in their type, a conversion from, say, `scala.immutable.List` will yield a `java.util.List`, where all mutation operations throw an "UnsupportedOperationException". Here's an example: + + scala> jul = List(1, 2, 3) + jul: java.util.List[Int] = [1, 2, 3] + scala> jul.add(7) + java.lang.UnsupportedOperationException + at java.util.AbstractList.add(AbstractList.java:131) + diff --git a/ko/overviews/collections/creating-collections-from-scratch.md b/ko/overviews/collections/creating-collections-from-scratch.md new file mode 100644 index 0000000000..37743e6565 --- /dev/null +++ b/ko/overviews/collections/creating-collections-from-scratch.md @@ -0,0 +1,58 @@ +--- +layout: overview-large +title: Creating Collections From Scratch + +disqus: true + +partof: collections +num: 16 +language: ko +--- + +You have syntax `List(1, 2, 3)` to create a list of three integers and `Map('A' -> 1, 'C' -> 2)` to create a map with two bindings. This is actually a universal feature of Scala collections. You can take any collection name and follow it by a list of elements in parentheses. The result will be a new collection with the given elements. Here are some more examples: + + Traversable() // An empty traversable object + List() // The empty list + List(1.0, 2.0) // A list with elements 1.0, 2.0 + Vector(1.0, 2.0) // A vector with elements 1.0, 2.0 + Iterator(1, 2, 3) // An iterator returning three integers. + Set(dog, cat, bird) // A set of three animals + HashSet(dog, cat, bird) // A hash set of the same animals + Map(a -> 7, 'b' -> 0) // A map from characters to integers + +"Under the covers" each of the above lines is a call to the `apply` method of some object. For instance, the third line above expands to + + List.apply(1.0, 2.0) + +So this is a call to the `apply` method of the companion object of the `List` class. That method takes an arbitrary number of arguments an constructs a list from them. Every collection class in the Scala library has a companion object with such an `apply` method. It does not matter whether the collection class represents a concrete implementation, like `List`, or `Stream` or `Vector`, do, or whether it is an abstract base class such as `Seq`, `Set` or `Traversable`. In the latter case, calling apply will produce some default implementation of the abstract base class. Examples: + + scala> List(1, 2, 3) + res17: List[Int] = List(1, 2, 3) + scala> Traversable(1, 2, 3) + res18: Traversable[Int] = List(1, 2, 3) + scala> mutable.Traversable(1, 2, 3) + res19: scala.collection.mutable.Traversable[Int] = ArrayBuffer(1, 2, 3) + +Besides `apply`, every collection companion object also defines a member `empty`, which returns an empty collection. So instead of `List()` you could write `List.empty`, instead of `Map()`, `Map.empty`, and so on. + +Descendants of `Seq` classes provide also other factory operations in their companion objects. These are summarized in the following table. In short, there's + +* `concat`, which concatenates an arbitrary number of traversables together, +* `fill` and `tabulate`, which generate single or multi-dimensional sequences of given dimensions initialized by some expression or tabulating function, +* `range`, which generates integer sequences with some constant step length, and +* `iterate`, which generates the sequence resulting from repeated application of a function to a start element. + +### Factory Methods for Sequences + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| `S.empty` | The empty sequence. | +| `S(x, y, z)` | A sequence consisting of elements `x, y, z`. | +| `S.concat(xs, ys, zs)` | The sequence obtained by concatenating the elements of `xs, ys, zs`. | +| `S.fill(n){e}` | A sequence of length `n` where each element is computed by expression `e`. | +| `S.fill(m, n){e}` | A sequence of sequences of dimension `m×n` where each element is computed by expression `e`. (exists also in higher dimensions). | +| `S.tabulate(n){f}` | A sequence of length `n` where the element at each index i is computed by `f(i)`. | +| `S.tabulate(m, n){f}` | A sequence of sequences of dimension `m×n` where the element at each index `(i, j)` is computed by `f(i, j)`. (exists also in higher dimensions). | +| `S.range(start, end)` | The sequence of integers `start` ... `end-1`. | +| `S.range(start, end, step)`| The sequence of integers starting with `start` and progressing by `step` increments up to, and excluding, the `end` value. | +| `S.iterate(x, n)(f)` | The sequence of length `n` with elements `x`, `f(x)`, `f(f(x))`, ... | diff --git a/ko/overviews/collections/equality.md b/ko/overviews/collections/equality.md new file mode 100644 index 0000000000..4258a943f1 --- /dev/null +++ b/ko/overviews/collections/equality.md @@ -0,0 +1,31 @@ +--- +layout: overview-large +title: Equality + +disqus: true + +partof: collections +num: 13 +language: ko +--- + +The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, `Set(1, 2, 3)` is unequal to `List(1, 2, 3)` even though they contain the same elements. On the other hand, within the same category, collections are equal if and only if they have the same elements (for sequences: the same elements in the same order). For example, `List(1, 2, 3) == Vector(1, 2, 3)`, and `HashSet(1, 2) == TreeSet(2, 1)`. + +It does not matter for the equality check whether a collection is mutable or immutable. For a mutable collection one simply considers its current elements at the time the equality test is performed. This means that a mutable collection might be equal to different collections at different times, depending what elements are added or removed. This is a potential trap when using a mutable collection as a key in a hashmap. Example: + + scala> import collection.mutable.{HashMap, ArrayBuffer} + import collection.mutable.{HashMap, ArrayBuffer} + scala> val buf = ArrayBuffer(1, 2, 3) + buf: scala.collection.mutable.ArrayBuffer[Int] = + ArrayBuffer(1, 2, 3) + scala> val map = HashMap(buf -> 3) + map: scala.collection.mutable.HashMap[scala.collection. + mutable.ArrayBuffer[Int],Int] = Map((ArrayBuffer(1, 2, 3),3)) + scala> map(buf) + res13: Int = 3 + scala> buf(0) += 1 + scala> map(buf) + java.util.NoSuchElementException: key not found: + ArrayBuffer(2, 2, 3) + +In this example, the selection in the last line will most likely fail because the hash-code of the array `xs` has changed in the second-to-last line. Therefore, the hash-code-based lookup will look at a different place than the one where `xs` was stored. diff --git a/ko/overviews/collections/iterators.md b/ko/overviews/collections/iterators.md new file mode 100644 index 0000000000..298f914648 --- /dev/null +++ b/ko/overviews/collections/iterators.md @@ -0,0 +1,176 @@ +--- +layout: overview-large +title: Iterators + +disqus: true + +partof: collections +num: 15 +language: ko +--- + +An iterator is not a collection, but rather a way to access the elements of a collection one by one. The two basic operations on an iterator `it` are `next` and `hasNext`. A call to `it.next()` will return the next element of the iterator and advance the state of the iterator. Calling `next` again on the same iterator will then yield the element one beyond the one returned previously. If there are no more elements to return, a call to `next` will throw a `NoSuchElementException`. You can find out whether there are more elements to return using [Iterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html)'s `hasNext` method. + +The most straightforward way to "step through" all the elements returned by an iterator `it` uses a while-loop: + + while (it.hasNext) + println(it.next()) + +Iterators in Scala also provide analogues of most of the methods that you find in the `Traversable`, `Iterable` and `Seq` classes. For instance, they provide a `foreach` method which executes a given procedure on each element returned by an iterator. Using `foreach`, the loop above could be abbreviated to: + + it foreach println + +As always, for-expressions can be used as an alternate syntax for expressions involving `foreach`, `map`, `withFilter`, and `flatMap`, so yet another way to print all elements returned by an iterator would be: + + for (elem <- it) println(elem) + +There's an important difference between the foreach method on iterators and the same method on traversable collections: When called to an iterator, `foreach` will leave the iterator at its end when it is done. So calling `next` again on the same iterator will fail with a `NoSuchElementException`. By contrast, when called on on a collection, `foreach` leaves the number of elements in the collection unchanged (unless the passed function adds to removes elements, but this is discouraged, because it may lead to surprising results). + +The other operations that Iterator has in common with `Traversable` have the same property. For instance, iterators provide a `map` method, which returns a new iterator: + + scala> val it = Iterator("a", "number", "of", "words") + it: Iterator[java.lang.String] = non-empty iterator + scala> it.map(_.length) + res1: Iterator[Int] = non-empty iterator + scala> res1 foreach println + 1 + 6 + 2 + 5 + scala> it.next() + java.util.NoSuchElementException: next on empty iterator + +As you can see, after the call to `it.map`, the `it` iterator has advanced to its end. + +Another example is the `dropWhile` method, which can be used to find the first elements of an iterator that has a certain property. For instance, to find the first word in the iterator above that has at least two characters you could write: + + scala> val it = Iterator("a", "number", "of", "words") + it: Iterator[java.lang.String] = non-empty iterator + scala> it dropWhile (_.length < 2) + res4: Iterator[java.lang.String] = non-empty iterator + scala> it.next() + res5: java.lang.String = number + +Note again that `it` has changed by the call to `dropWhile`: it now points to the second word "number" in the list. In fact, `it` and the result `res4` returned by `dropWhile` will return exactly the same sequence of elements. + +There is only one standard operation which allows to re-use the same iterator: The call + + val (it1, it2) = it.duplicate + +gives you _two_ iterators which each return exactly the same elements as the iterator `it`. The two iterators work independently; advancing one does not affect the other. By contrast the original iterator `it` is advanced to its end by `duplicate` and is thus rendered unusable. + +In summary, iterators behave like collections _if one never accesses an iterator again after invoking a method on it_. The Scala collection libraries make this explicit with an abstraction [TraversableOnce](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/TraversableOnce.html), which is a common superclass of [Traversable](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Traversable.html) and [Iterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html). As the name implies, `TraversableOnce` objects can be traversed using `foreach` but the state of that object after the traversal is not specified. If the `TraversableOnce` object is in fact an `Iterator`, it will be at its end after the traversal, but if it is a `Traversable`, it will still exist as before. A common use case of `TraversableOnce` is as an argument type for methods that can take either an iterator or a traversable as argument. An example is the appending method `++` in class `Traversable`. It takes a `TraversableOnce` parameter, so you can append elements coming from either an iterator or a traversable collection. + +All operations on iterators are summarized below. + +### Operations in class Iterator + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Abstract Methods:** | | +| `it.next()` | Returns next element on iterator and advances past it. | +| `it.hasNext` | Returns `true` if `it` can return another element. | +| **Variations:** | | +| `it.buffered` | A buffered iterator returning all elements of `it`. | +| `it grouped size` | An iterator that yields the elements elements returned by `it` in fixed-sized sequence "chunks". | +| `xs sliding size` | An iterator that yields the elements elements returned by `it` in sequences representing a sliding fixed-sized window. | +| **Duplication:** | | +| `it.duplicate` | A pair of iterators that each independently return all elements of `it`. | +| **Additions:** | | +| `it ++ jt` | An iterator returning all elements returned by iterator `it`, followed by all elements returned by iterator `jt`. | +| `it padTo (len, x)` | The iterator that first returns all elements of `it` and then follows that by copies of `x` until length `len` elements are returned overall. | +| **Maps:** | | +| `it map f` | The iterator obtained from applying the function `f` to every element returned from `it`. | +| `it flatMap f` | The iterator obtained from applying the iterator-valued function f to every element in `it` and appending the results. | +| `it collect f` | The iterator obtained from applying the partial function `f` to every element in `it` for which it is defined and collecting the results. | +| **Conversions:** | | +| `it.toArray` | Collects the elements returned by `it` in an array. | +| `it.toList` | Collects the elements returned by `it` in a list. | +| `it.toIterable` | Collects the elements returned by `it` in an iterable. | +| `it.toSeq` | Collects the elements returned by `it` in a sequence. | +| `it.toIndexedSeq` | Collects the elements returned by `it` in an indexed sequence. | +| `it.toStream` | Collects the elements returned by `it` in a stream. | +| `it.toSet` | Collects the elements returned by `it` in a set. | +| `it.toMap` | Collects the key/value pairs returned by `it` in a map. | +| **Coying:** | | +| `it copyToBuffer buf` | Copies all elements returned by `it` to buffer `buf`. | +| `it copyToArray(arr, s, n)`| Copies at most `n` elements returned by `it` to array `arr` starting at index `s`. The last two arguments are optional. | +| **Size Info:** | | +| `it.isEmpty` | Test whether the iterator is empty (opposite of `hasNext`). | +| `it.nonEmpty` | Test whether the collection contains elements (alias of `hasNext`). | +| `it.size` | The number of elements returned by `it`. Note: `it` will be at its end after this operation! | +| `it.length` | Same as `it.size`. | +| `it.hasDefiniteSize` | Returns `true` if `it` is known to return finitely many elements (by default the same as `isEmpty`). | +| **Element Retrieval Index Search:**| | +| `it find p` | An option containing the first element returned by `it` that satisfies `p`, or `None` is no element qualifies. Note: The iterator advances to after the element, or, if none is found, to the end. | +| `it indexOf x` | The index of the first element returned by `it` that equals `x`. Note: The iterator advances past the position of this element. | +| `it indexWhere p` | The index of the first element returned by `it` that satisfies `p`. Note: The iterator advances past the position of this element. | +| **Subiterators:** | | +| `it take n` | An iterator returning of the first `n` elements of `it`. Note: it will advance to the position after the `n`'th element, or to its end, if it contains less than `n` elements. | +| `it drop n` | The iterator that starts with the `(n+1)`'th element of `it`. Note: `it` will advance to the same position. | +| `it slice (m,n)` | The iterator that returns a slice of the elements returned from it, starting with the `m`'th element and ending before the `n`'th element. | +| `it takeWhile p` | An iterator returning elements from `it` as long as condition `p` is true. | +| `it dropWhile p` | An iterator skipping elements from `it` as long as condition `p` is `true`, and returning the remainder. | +| `it filter p` | An iterator returning all elements from `it` that satisfy the condition `p`. | +| `it withFilter p` | Same as `it` filter `p`. Needed so that iterators can be used in for-expressions. | +| `it filterNot p` | An iterator returning all elements from `it` that do not satisfy the condition `p`. | +| **Subdivisions:** | | +| `it partition p` | Splits `it` into a pair of two iterators; one returning all elements from `it` that satisfy the predicate `p`, the other returning all elements from `it` that do not. | +| **Element Conditions:** | | +| `it forall p` | A boolean indicating whether the predicate p holds for all elements returned by `it`. | +| `it exists p` | A boolean indicating whether the predicate p holds for some element in `it`. | +| `it count p` | The number of elements in `it` that satisfy the predicate `p`. | +| **Folds:** | | +| `(z /: it)(op)` | Apply binary operation `op` between successive elements returned by `it`, going left to right and starting with `z`. | +| `(it :\ z)(op)` | Apply binary operation `op` between successive elements returned by `it`, going right to left and starting with `z`. | +| `it.foldLeft(z)(op)` | Same as `(z /: it)(op)`. | +| `it.foldRight(z)(op)` | Same as `(it :\ z)(op)`. | +| `it reduceLeft op` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going left to right. | +| `it reduceRight op` | Apply binary operation `op` between successive elements returned by non-empty iterator `it`, going right to left. | +| **Specific Folds:** | | +| `it.sum` | The sum of the numeric element values returned by iterator `it`. | +| `it.product` | The product of the numeric element values returned by iterator `it`. | +| `it.min` | The minimum of the ordered element values returned by iterator `it`. | +| `it.max` | The maximum of the ordered element values returned by iterator `it`. | +| **Zippers:** | | +| `it zip jt` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`. | +| `it zipAll (jt, x, y)` | An iterator of pairs of corresponding elements returned from iterators `it` and `jt`, where the shorter iterator is extended to match the longer one by appending elements `x` or `y`. | +| `it.zipWithIndex` | An iterator of pairs of elements returned from `it` with their indices. | +| **Update:** | | +| `it patch (i, jt, r)` | The iterator resulting from `it` by replacing `r` elements starting with `i` by the patch iterator `jt`. | +| **Comparison:** | | +| `it sameElements jt` | A test whether iterators it and `jt` return the same elements in the same order. Note: At least one of `it` and `jt` will be at its end after this operation. | +| **Strings:** | | +| `it addString (b, start, sep, end)`| Adds a string to `StringBuilder` `b` which shows all elements returned by `it` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional. | +| `it mkString (start, sep, end)` | Converts the collection to a string which shows all elements returned by `it` between separators `sep` enclosed in strings `start` and `end`. `start`, `sep`, `end` are all optional. | + +### Buffered iterators + +Sometimes you want an iterator that can "look ahead", so that you can inspect the next element to be returned without advancing past that element. Consider for instance, the task to skip leading empty strings from an iterator that returns a sequence of strings. You might be tempted to write the following + + + def skipEmptyWordsNOT(it: Iterator[String]) = + while (it.next().isEmpty) {} + +But looking at this code more closely, it's clear that this is wrong: The code will indeed skip leading empty strings, but it will also advance `it` past the first non-empty string! + +The solution to this problem is to use a buffered iterator. Class [BufferedIterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/BufferedIterator.html) is a subclass of [Iterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html), which provides one extra method, `head`. Calling `head` on a buffered iterator will return its first element but will not advance the iterator. Using a buffered iterator, skipping empty words can be written as follows. + + def skipEmptyWords(it: BufferedIterator[String]) = + while (it.head.isEmpty) { it.next() } + +Every iterator can be converted to a buffered iterator by calling its `buffered` method. Here's an example: + + scala> val it = Iterator(1, 2, 3, 4) + it: Iterator[Int] = non-empty iterator + scala> val bit = it.buffered + bit: java.lang.Object with scala.collection. + BufferedIterator[Int] = non-empty iterator + scala> bit.head + res10: Int = 1 + scala> bit.next() + res11: Int = 1 + scala> bit.next() + res11: Int = 2 + +Note that calling `head` on the buffered iterator `bit` does not advance it. Therefore, the subsequent call `bit.next()` returns the same value as `bit.head`. diff --git a/ko/overviews/collections/maps.md b/ko/overviews/collections/maps.md new file mode 100644 index 0000000000..9030033abb --- /dev/null +++ b/ko/overviews/collections/maps.md @@ -0,0 +1,164 @@ +--- +layout: overview-large +title: Maps + +disqus: true + +partof: collections +num: 7 +language: ko +--- + +A [Map](http://www.scala-lang.org/api/current/scala/collection/Map.html) is an [Iterable](http://www.scala-lang.org/api/current/scala/collection/Iterable.html) consisting of pairs of keys and values (also named _mappings_ or _associations_). Scala's [Predef](http://www.scala-lang.org/api/current/scala/Predef$.html) class offers an implicit conversion that lets you write `key -> value` as an alternate syntax for the pair `(key, value)`. For instance `Map("x" -> 24, "y" -> 25, "z" -> 26)` means exactly the same as `Map(("x", 24), ("y", 25), ("z", 26))`, but reads better. + +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. +* **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. +* **Transformations** `filterKeys` and `mapValues`, which produce a new map by filtering and transforming bindings of an existing map. + +### Operations in Class Map ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Lookups:** | | +| `ms get k` |The value associated with key `k` in map `ms` as an option, `None` if not found.| +| `ms(k)` |(or, written out, `ms apply k`) The value associated with key `k` in map `ms`, or exception if not found.| +| `ms getOrElse (k, d)` |The value associated with key `k` in map `ms`, or the default value `d` if not found.| +| `ms contains k` |Tests whether `ms` contains a mapping for key `k`.| +| `ms isDefinedAt k` |Same as `contains`. | +| **Additions and Updates:**| | +| `ms + (k -> v)` |The map containing all mappings of `ms` as well as the mapping `k -> v` from key `k` to value `v`.| +| `ms + (k -> v, l -> w)` |The map containing all mappings of `ms` as well as the given key/value pairs.| +| `ms ++ kvs` |The map containing all mappings of `ms` as well as all key/value pairs of `kvs`.| +| `ms updated (k, v)` |Same as `ms + (k -> v)`.| +| **Removals:** | | +| `ms - k` |The map containing all mappings of `ms` except for any mapping of key `k`.| +| `ms - (k, 1, m)` |The map containing all mappings of `ms` except for any mapping with the given keys.| +| `ms -- ks` |The map containing all mappings of `ms` except for any mapping with a key in `ks`.| +| **Subcollections:** | | +| `ms.keys` |An iterable containing each key in `ms`. | +| `ms.keySet` |A set containing each key in `ms`. | +| `ms.keyIterator` |An iterator yielding each key in `ms`. | +| `ms.values` |An iterable containing each value associated with a key in `ms`.| +| `ms.valuesIterator` |An iterator yielding each value associated with a key in `ms`.| +| **Transformation:** | | +| `ms filterKeys p` |A map view containing only those mappings in `ms` where the key satisfies predicate `p`.| +| `ms mapValues f` |A map view resulting from applying function `f` to each value associated with a key in `ms`.| + +Mutable maps support in addition the operations summarized in the following table. + + +### Operations in Class mutable.Map ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Additions and Updates:**| | +| `ms(k) = v` |(Or, written out, `ms.update(x, v)`). Adds mapping from key `k` to value `v` to map ms as a side effect, overwriting any previous mapping of `k`.| +| `ms += (k -> v)` |Adds mapping from key `k` to value `v` to map `ms` as a side effect and returns `ms` itself.| +| `ms += (k -> v, l -> w)` |Adds the given mappings to `ms` as a side effect and returns `ms` itself.| +| `ms ++= kvs` |Adds all mappings in `kvs` to `ms` as a side effect and returns `ms` itself.| +| `ms put (k, v)` |Adds mapping from key `k` to value `v` to `ms` and returns any value previously associated with `k` as an option.| +| `ms getOrElseUpdate (k, d)`|If key `k` is defined in map `ms`, return its associated value. Otherwise, update `ms` with the mapping `k -> d` and return `d`.| +| **Additions and Updates:**| | +| `ms -= k` |Removes mapping with key `k` from ms as a side effect and returns `ms` itself.| +| `ms -= (k, l, m)` |Removes mappings with the given keys from `ms` as a side effect and returns `ms` itself.| +| `ms --= ks` |Removes all keys in `ks` from `ms` as a side effect and returns `ms` itself.| +| `ms remove k` |Removes any mapping with key `k` from `ms` and returns any value previously associated with `k` as an option.| +| `ms retain p` |Keeps only those mappings in `ms` that have a key satisfying predicate `p`.| +| `ms.clear()` |Removes all mappings from `ms`. | +| **Transformation:** | | +| `ms transform f` |Transforms all associated values in map `ms` with function `f`.| +| **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. As is the for sets, mutable maps also support the non-destructive addition operations `+`, `-`, and `updated`, but they are used less frequently because they involve a copying of the mutable map. Instead, a mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There are 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`: + + scala> def f(x: String) = { + println("taking my time."); sleep(100) + x.reverse } + f: (x: String)String + +Assume further that `f` has no side-effects, so invoking it again with the same argument will always yield the same result. In that case you could save time by storing previously computed bindings of argument and results of `f` in a map and only computing the result of `f` if a result of an argument was not found there. One could say the map is a _cache_ for the computations of the function `f`. + + val cache = collection.mutable.Map[String, String]() + cache: scala.collection.mutable.Map[String,String] = Map() + +You can now create a more efficient caching version of the `f` function: + + scala> def cachedF(s: 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 + +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: + + def cachedF(arg: String) = cache get arg match { + case Some(result) => result + case None => + val result = f(x) + cache(arg) = result + result + } + +### Synchronized Sets and Maps ### + +To get a thread-safe mutable map, you can mix the `SynchronizedMap` trait trait into whatever particular map implementation you desire. For example, you can mix `SynchronizedMap` into `HashMap`, as shown in the code below. This example begins with an import of two traits, `Map` and `SynchronizedMap`, and one class, `HashMap`, from package `scala.collection.mutable`. The rest of the example is the definition of singleton object `MapMaker`, which declares one method, `makeMap`. The `makeMap` method declares its result type to be a mutable map of string keys to string values. + + import scala.collection.mutable.{Map, + SynchronizedMap, HashMap} + object MapMaker { + def makeMap: Map[String, String] = { + new HashMap[String, String] with + SynchronizedMap[String, String] { + override def default(key: String) = + "Why do you want to know?" + } + } + } + +
Mixing in the `SynchronizedMap` trait.
+ +The first statement inside the body of `makeMap` constructs a new mutable `HashMap` that mixes in the `SynchronizedMap` trait: + + new HashMap[String, String] with + SynchronizedMap[String, String] + +Given this code, the Scala compiler will generate a synthetic subclass of `HashMap` that mixes in `SynchronizedMap`, and create (and return) an instance of it. This synthetic class will also override a method named `default`, because of this code: + + override def default(key: String) = + "Why do you want to know?" + +If you ask a map to give you the value for a particular key, but it doesn't have a mapping for that key, you'll by default get a `NoSuchElementException`. If you define a new map class and override the `default` method, however, your new map will return the value returned by `default` when queried with a non-existent key. Thus, the synthetic `HashMap` subclass generated by the compiler from the code in the synchronized map code will return the somewhat curt response string, `"Why do you want to know?"`, when queried with a non-existent key. + +Because the mutable map returned by the `makeMap` method mixes in the `SynchronizedMap` trait, it can be used by multiple threads at once. Each access to the map will be synchronized. Here's an example of the map being used, by one thread, in the interpreter: + + scala> val capital = MapMaker.makeMap + capital: scala.collection.mutable.Map[String,String] = Map() + scala> capital ++ List("US" -> "Washington", + "Paris" -> "France", "Japan" -> "Tokyo") + res0: scala.collection.mutable.Map[String,String] = + Map(Paris -> France, US -> Washington, Japan -> Tokyo) + scala> capital("Japan") + res1: String = Tokyo + scala> capital("New Zealand") + res2: String = Why do you want to know? + scala> capital += ("New Zealand" -> "Wellington") + scala> capital("New Zealand") + res3: String = Wellington + +You can create synchronized sets similarly to the way you create synchronized maps. For example, you could create a synchronized `HashSet` by mixing in the `SynchronizedSet` trait, like this: + + import scala.collection.mutable + val synchroSet = + new mutable.HashSet[Int] with + mutable.SynchronizedSet[Int] + +Finally, if you are thinking of using synchronized collections, you may also wish to consider the concurrent collections of `java.util.concurrent` instead. diff --git a/ko/overviews/collections/migrating-from-scala-27.md b/ko/overviews/collections/migrating-from-scala-27.md new file mode 100644 index 0000000000..a4e774f6ed --- /dev/null +++ b/ko/overviews/collections/migrating-from-scala-27.md @@ -0,0 +1,45 @@ +--- +layout: overview-large +title: Migrating from Scala 2.7 + +disqus: true + +partof: collections +num: 18 +outof: 18 +language: ko +--- + +Porting your existing Scala applications to use the new collections should be almost automatic. There are only a couple of possible issues to take care of. + +Generally, the old functionality of Scala 2.7 collections has been left in place. Some features have been deprecated, which means they will removed in some future release. You will get a _deprecation warning_ when you compile code that makes use of these features in Scala 2.8. In a few places deprecation was unfeasible, because the operation in question was retained in 2.8, but changed in meaning or performance characteristics. These cases will be flagged with _migration warnings_ when compiled under 2.8. To get full deprecation and migration warnings with suggestions how to change your code, pass the `-deprecation` and `-Xmigration` flags to `scalac` (note that `-Xmigration` is an extended option, so it starts with an `X`.) You can also pass the same options to the `scala` REPL to get the warnings in an interactive session. Example: + + >scala -deprecation -Xmigration + Welcome to Scala version 2.8.0.final + Type in expressions to have them evaluated. + Type :help for more information. + scala> val xs = List((1, 2), (3, 4)) + xs: List[(Int, Int)] = List((1,2), (3,4)) + scala> List.unzip(xs) + :7: warning: method unzip in object List is deprecated: use xs.unzip instead of List.unzip(xs) + List.unzip(xs) + ^ + res0: (List[Int], List[Int]) = (List(1, 3),List(2, 4)) + scala> xs.unzip + res1: (List[Int], List[Int]) = (List(1, 3),List(2, 4)) + scala> val m = xs.toMap + m: scala.collection.immutable.Map[Int,Int] = Map((1,2), (3,4)) + scala> m.keys + :8: warning: method keys in trait MapLike has changed semantics: + As of 2.8, keys returns Iterable[A] rather than Iterator[A]. + m.keys + ^ + res2: Iterable[Int] = Set(1, 3) + +There are two parts of the old libraries which have been replaced wholesale, and for which deprecation warnings were not feasible. + +1. The previous `scala.collection.jcl` package is gone. This package tried to mimick some of the Java collection library design in Scala, but in doing so broke many symmetries. Most people who wanted Java collections bypassed `jcl` and used `java.util` directly. Scala 2.8 offers automatic conversion mechanisms between both collection libraries in the [JavaConversions]({{ site.baseurl }}/overviews/collections/conversions-between-java-and-scala-collections.md) object which replaces the `jcl` package. +2. Projections have been generalized and cleaned up and are now available as views. It seems that projections were used rarely, so not much code should be affected by this change. + +So, if your code uses either `jcl` or projections there might be some minor rewriting to do. + diff --git a/ko/overviews/collections/overview.md b/ko/overviews/collections/overview.md old mode 100755 new mode 100644 index 3fca9bcbc7..3d9ba47f82 --- a/ko/overviews/collections/overview.md +++ b/ko/overviews/collections/overview.md @@ -9,16 +9,12 @@ num: 2 language: ko --- -스칼라 컬렉션에서는 구조적으로 불변성(immutable)인 컬렉션과 가변성(mutable)인 컬렉션을 -구분한다. +스칼라 컬렉션에서는 불변성(immutable)인 컬렉션과 가변성(mutable)인 컬렉션을 +체계적으로 구분한다. _가변(mutable)_ 컬렉션은 변경하거나 확장이 가능하다. 즉, +부작용을 통해 원소를 변경하거나 추가하거나 삭제할 수 있다. 반대로 _불변(immutable)_ +컬렉션은 결코 변화되지 않는다. 원소 삭제, 추가, 변경을 모방하는 연산이 있긴 하지만, +그런 경우 새로운 컬렉션이 반환될 뿐 원래의 컬렉션은 변하지 않는다. -Scala collections systematically distinguish between mutable and -immutable collections. A _mutable_ collection can be updated or -extended in place. This means you can change, add, or remove elements -of a collection as a side effect. _Immutable_ collections, by -contrast, never change. You have still operations that simulate -additions, removals, or updates, but those operations will in each -case return a new collection and leave the old collection unchanged. All collection classes are found in the package `scala.collection` or one of its sub-packages `mutable`, `immutable`, and `generic`. Most @@ -142,4 +138,5 @@ This behavior which is implemented everywhere in the collections libraries is ca Most of the classes in the collections hierarchy exist in three variants: root, mutable, and immutable. The only exception is the Buffer trait which only exists as a mutable collection. -In the following, we will review these classes one by one. \ No newline at end of file +In the following, we will review these classes one by one. + diff --git a/ko/overviews/collections/performance-characteristics.md b/ko/overviews/collections/performance-characteristics.md new file mode 100644 index 0000000000..e621a0c91a --- /dev/null +++ b/ko/overviews/collections/performance-characteristics.md @@ -0,0 +1,85 @@ +--- +layout: overview-large +title: Performance Characteristics + +disqus: true + +partof: collections +num: 12 +language: ko +--- + +The previous explanations have made it clear that different collection types have different performance characteristics. That's often the primary reason for picking one collection type over another. You can see the performance characteristics of some common operations on collections summarized in the following two tables. + +Performance characteristics of sequence types: + +| | head | tail | apply | update| prepend | append | insert | +| -------- | ---- | ---- | ---- | ---- | ---- | ---- | ---- | +| **immutable** | | | | | | | | +| `List` | C | C | L | L | C | L | - | +| `Stream` | C | C | L | L | C | L | - | +| `Vector` | eC | eC | eC | eC | eC | eC | - | +| `Stack` | C | C | L | L | C | C | L | +| `Queue` | aC | aC | L | L | L | C | - | +| `Range` | C | C | C | - | - | - | - | +| `String` | C | L | C | L | L | L | - | +| **mutable** | | | | | | | | +| `ArrayBuffer` | C | L | C | C | L | aC | L | +| `ListBuffer` | C | L | L | L | C | C | L | +|`StringBuilder`| C | L | C | C | L | aC | L | +| `MutableList` | C | L | L | L | C | C | L | +| `Queue` | C | L | L | L | C | C | L | +| `ArraySeq` | C | L | C | C | - | - | - | +| `Stack` | C | L | L | L | C | L | L | +| `ArrayStack` | C | L | C | C | aC | L | L | +| `Array` | C | L | C | C | - | - | - | + +Performance characteristics of set and map types: + +| | lookup | add | remove | min | +| -------- | ---- | ---- | ---- | ---- | +| **immutable** | | | | | +| `HashSet`/`HashMap`| eC | eC | eC | L | +| `TreeSet`/`TreeMap`| Log | Log | Log | Log | +| `BitSet` | C | L | L | eC1| +| `ListMap` | L | L | L | L | +| **mutable** | | | | | +| `HashSet`/`HashMap`| eC | eC | eC | L | +| `WeakHashMap` | eC | eC | eC | L | +| `BitSet` | C | aC | C | eC1| +| `TreeSet` | Log | Log | Log | Log | + +Footnote: 1 Assuming bits are densely packed. + +The entries in these two tables are explained as follows: + +| | | +| --- | ---- | +| **C** | The operation takes (fast) constant time. | +| **eC** | The operation takes effectively constant time, but this might depend on some assumptions such as maximum length of a vector or distribution of hash keys.| +| **aC** | The operation takes amortized constant time. Some invocations of the operation might take longer, but if many operations are performed on average only constant time per operation is taken. | +| **Log** | The operation takes time proportional to the logarithm of the collection size. | +| **L** | The operation is linear, that is it takes time proportional to the collection size. | +| **-** | The operation is not supported. | + +The first table treats sequence types--both immutable and mutable--with the following operations: + +| | | +| --- | ---- | +| **head** | Selecting the first element of the sequence. | +| **tail** | Producing a new sequence that consists of all elements except the first one. | +| **apply** | Indexing. | +| **update** | Functional update (with `updated`) for immutable sequences, side-effecting update (with `update` for mutable sequences. | +| **prepend**| Adding an element to the front of the sequence. For immutable sequences, this produces a new sequence. For mutable sequences it modified the existing sequence. | +| **append** | Adding an element and the end of the sequence. For immutable sequences, this produces a new sequence. For mutable sequences it modified the existing sequence. | +| **insert** | Inserting an element at an arbitrary position in the sequence. This is only supported directly for mutable sequences. | + +The second table treats mutable and immutable sets and maps with the following operations: + +| | | +| --- | ---- | +| **lookup** | Testing whether an element is contained in set, or selecting a value associated with a key. | +| **add** | Adding a new element to a set or key/value pair to a map. | +| **remove** | Removing an element from a set or a key from a map. | +| **min** | The smallest element of the set, or the smallest key of a map. | + diff --git a/ko/overviews/collections/seqs.md b/ko/overviews/collections/seqs.md new file mode 100644 index 0000000000..a58da9c782 --- /dev/null +++ b/ko/overviews/collections/seqs.md @@ -0,0 +1,101 @@ +--- +layout: overview-large +title: The sequence traits Seq, IndexedSeq, and LinearSeq + +disqus: true + +partof: collections +num: 5 +language: ko +--- + +The [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) trait represents sequences. A sequence is a kind of iterable that has a `length` and whose elements have fixed index positions, starting from `0`. + +The operations on sequences, summarized in the table below, fall into the following categories: + +* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of two sequences even if one of the sequences has infinite length. +* **Index search operations** `indexOf`, `lastIndexOf`, `indexofSlice`, `lastIndexOfSlice`, `indexWhere`, `lastIndexWhere`, `segmentLength`, `prefixLength`, which return the index of an element equal to a given value or matching some predicate. +* **Addition operations** `+:`, `:+`, `padTo`, which return new sequences obtained by adding elements at the front or the end of a sequence. +* **Update operations** `updated`, `patch`, which return a new sequence obtained by replacing some elements of the original sequence. +* **Sorting operations** `sorted`, `sortWith`, `sortBy`, which sort sequence elements according to various criteria. +* **Reversal operations** `reverse`, `reverseIterator`, `reverseMap`, which yield or process sequence elements in reverse order. +* **Comparisons** `startsWith`, `endsWith`, `contains`, `containsSlice`, `corresponds`, which relate two sequences or search an element in a sequence. +* **Multiset** operations `intersect`, `diff`, `union`, `distinct`, which perform set-like operations on the elements of two sequences or remove duplicates. + +If a sequence is mutable, it offers in addition a side-effecting `update` method, which lets sequence elements be updated. As always in Scala, syntax like `seq(idx) = elem` is just a shorthand for `seq.update(idx, elem)`, so `update` gives convenient assignment syntax for free. Note the difference between `update` and `updated`. `update` changes a sequence element in place, and is only available for mutable sequences. `updated` is available for all sequences and always returns a new sequence instead of modifying the original. + +### Operations in Class Seq ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Indexing and Length:** | | +| `xs(i)` |(or, written out, `xs apply i`). The element of `xs` at index `i`.| +| `xs isDefinedAt i` |Tests whether `i` is contained in `xs.indices`.| +| `xs.length` |The length of the sequence (same as `size`).| +| `xs.lengthCompare ys` |Returns `-1` if `xs` is shorter than `ys`, `+1` if it is longer, and `0` is they have the same length. Works even if one if the sequences is infinite.| +| `xs.indices` |The index range of `xs`, extending from `0` to `xs.length - 1`.| +| **Index Search:** | | +| `xs indexOf x` |The index of the first element in `xs` equal to `x` (several variants exist).| +| `xs lastIndexOf x` |The index of the last element in `xs` equal to `x` (several variants exist).| +| `xs indexOfSlice ys` |The first index of `xs` such that successive elements starting from that index form the sequence `ys`.| +| `xs lastIndexOfSlice ys` |The last index of `xs` such that successive elements starting from that index form the sequence `ys`.| +| `xs indexWhere p` |The index of the first element in xs that satisfies `p` (several variants exist).| +| `xs segmentLength (p, i)`|The length of the longest uninterrupted segment of elements in `xs`, starting with `xs(i)`, that all satisfy the predicate `p`.| +| `xs prefixLength p` |The length of the longest prefix of elements in `xs` that all satisfy the predicate `p`.| +| **Additions:** | | +| `x +: xs` |A new sequence that consists of `x` prepended to `xs`.| +| `xs :+ x` |A new sequence that consists of `x` appended to `xs`.| +| `xs padTo (len, x)` |The sequence resulting from appending the value `x` to `xs` until length `len` is reached.| +| **Updates:** | | +| `xs patch (i, ys, r)` |The sequence resulting from replacing `r` elements of `xs` starting with `i` by the patch `ys`.| +| `xs updated (i, x)` |A copy of `xs` with the element at index `i` replaced by `x`.| +| `xs(i) = x` |(or, written out, `xs.update(i, x)`, only available for `mutable.Seq`s). Changes the element of `xs` at index `i` to `x`.| +| **Sorting:** | | +| `xs.sorted` |A new sequence obtained by sorting the elements of `xs` using the standard ordering of the element type of `xs`.| +| `xs sortWith lt` |A new sequence obtained by sorting the elements of `xs` using `lt` as comparison operation.| +| `xs sortBy f` |A new sequence obtained by sorting the elements of `xs`. Comparison between two elements proceeds by mapping the function `f` over both and comparing the results.| +| **Reversals:** | | +| `xs.reverse` |A sequence with the elements of `xs` in reverse order.| +| `xs.reverseIterator` |An iterator yielding all the elements of `xs` in reverse order.| +| `xs reverseMap f` |A sequence obtained by mapping `f` over the elements of `xs` in reverse order.| +| **Comparisons:** | | +| `xs startsWith ys` |Tests whether `xs` starts with sequence `ys` (several variants exist).| +| `xs endsWith ys` |Tests whether `xs` ends with sequence `ys` (several variants exist).| +| `xs contains x` |Tests whether `xs` has an element equal to `x`.| +| `xs containsSlice ys` |Tests whether `xs` has a contiguous subsequence equal to `ys`.| +| `(xs corresponds ys)(p)` |Tests whether corresponding elements of `xs` and `ys` satisfy the binary predicate `p`.| +| **Multiset Operations:** | | +| `xs intersect ys` |The multi-set intersection of sequences `xs` and `ys` that preserves the order of elements in `xs`.| +| `xs diff ys` |The multi-set difference of sequences `xs` and `ys` that preserves the order of elements in `xs`.| +| `xs union ys` |Multiset union; same as `xs ++ ys`.| +| `xs.distinct` |A subsequence of `xs` that contains no duplicated element.| + +Trait [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) has two subtraits [LinearSeq](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html), and [IndexedSeq](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html). These do not add any new operations, but each offers different performance characteristics: A linear sequence has efficient `head` and `tail` operations, whereas an indexed sequence has efficient `apply`, `length`, and (if mutable) `update` operations. Frequently used linear sequences are `scala.collection.immutable.List` and `scala.collection.immutable.Stream`. Frequently used indexed sequences are `scala.Array` and `scala.collection.mutable.ArrayBuffer`. The `Vector` class provides an interesting compromise between indexed and linear access. It has both effectively constant time indexing overhead and constant time linear access overhead. Because of this, vectors are a good foundation for mixed access patterns where both indexed and linear accesses are used. You'll learn more on vectors [later](#vectors). + +### Buffers ### + +An important sub-category of mutable sequences is `Buffer`s. They allow not only updates of existing elements but also element insertions, element removals, and efficient additions of new elements at the end of the buffer. The principal new methods supported by a buffer are `+=` and `++=` for element addition at the end, `+=:` and `++=:` for addition at the front, `insert` and `insertAll` for element insertions, as well as `remove` and `-=` for element removal. These operations are summarized in the following table. + +Two often used implementations of buffers are `ListBuffer` and `ArrayBuffer`. As the name implies, a `ListBuffer` is backed by a `List`, and supports efficient conversion of its elements to a `List`, whereas an `ArrayBuffer` is backed by an array, and can be quickly converted into one. + +#### Operations in Class Buffer #### + +| WHAT IT IS | WHAT IT DOES| +| ------ | ------ | +| **Additions:** | | +| `buf += x` |Appends element `x` to buffer, and returns `buf` itself as result.| +| `buf += (x, y, z)` |Appends given elements to buffer.| +| `buf ++= xs` |Appends all elements in `xs` to buffer.| +| `x +=: buf` |Prepends element `x` to buffer.| +| `xs ++=: buf` |Prepends all elements in `xs` to buffer.| +| `buf insert (i, x)` |Inserts element `x` at index `i` in buffer.| +| `buf insertAll (i, xs)` |Inserts all elements in `xs` at index `i` in buffer.| +| **Removals:** | | +| `buf -= x` |Removes element `x` from buffer.| +| `buf remove i` |Removes element at index `i` from buffer.| +| `buf remove (i, n)` |Removes `n` elements starting at index `i` from buffer.| +| `buf trimStart n` |Removes first `n` elements from buffer.| +| `buf trimEnd n` |Removes last `n` elements from buffer.| +| `buf.clear()` |Removes all elements from buffer.| +| **Cloning:** | | +| `buf.clone` |A new buffer with the same elements as `buf`.| diff --git a/ko/overviews/collections/sets.md b/ko/overviews/collections/sets.md new file mode 100644 index 0000000000..35ec5faa0c --- /dev/null +++ b/ko/overviews/collections/sets.md @@ -0,0 +1,150 @@ +--- +layout: overview-large +title: Sets + +disqus: true + +partof: collections +num: 6 +language: ko +--- + +`Set`s are `Iterable`s that contain no duplicate elements. The operations on sets are summarized in the following table for general sets and in the table after that for mutable sets. They fall into the following categories: + +* **Tests** `contains`, `apply`, `subsetOf`. The `contains` method asks whether a set contains a given element. The `apply` method for a set is the same as `contains`, so `set(elem)` is the same as `set contains elem`. That means sets can also be used as test functions that return true for the elements they contain. + +For example + + + 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 + + +* **Additions** `+` and `++`, which add one or more elements to a set, yielding a new set. +* **Removals** `-`, `--`, which remove one or more elements from a set, yielding a new set. +* **Set operations** for union, intersection, and set difference. Each of these operations exists in two forms: alphabetic and symbolic. The alphabetic versions are `intersect`, `union`, and `diff`, whereas the symbolic versions are `&`, `|`, and `&~`. In fact, the `++` that Set inherits from `Traversable` can be seen as yet another alias of `union` or `|`, except that `++` takes a `Traversable` argument whereas `union` and `|` take sets. + +### Operations in Class Set ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Tests:** | | +| `xs contains x` |Tests whether `x` is an element of `xs`. | +| `xs(x)` |Same as `xs contains x`. | +| `xs subsetOf ys` |Tests whether `xs` is a subset of `ys`. | +| **Additions:** | | +| `xs + x` |The set containing all elements of `xs` as well as `x`.| +| `xs + (x, y, z)` |The set containing all elements of `xs` as well as the given additional elements.| +| `xs ++ ys` |The set containing all elements of `xs` as well as all elements of `ys`.| +| **Tests:** | | +| `xs - x` |The set containing all elements of `xs` except `x`.| +| `xs - (x, y, z)` |The set containing all elements of `xs` except the given elements.| +| `xs -- ys` |The set containing all elements of `xs` except the elements of `ys`.| +| `xs.empty` |An empty set of the same class as `xs`. | +| **Binary Operations:** | | +| `xs & ys` |The set intersection of `xs` and `ys`. | +| `xs intersect ys` |Same as `xs & ys`. | +| xs | ys |The set union of `xs` and `ys`. | +| `xs union ys` |Same as xs | ys. | +| `xs &~ ys` |The set difference of `xs` and `ys`. | +| `xs diff ys` |Same as `xs &~ ys`. | + +Mutable sets offer in addition methods to add, remove, or update elements, which are summarized in below. + +### Operations in Class mutable.Set ### + +| WHAT IT IS | WHAT IT DOES | +| ------ | ------ | +| **Additions:** | | +| `xs += x` |Adds element `x` to set `xs` as a side effect and returns `xs` itself.| +| `xs += (x, y, z)` |Adds the given elements to set `xs` as a side effect and returns `xs` itself.| +| `xs ++= ys` |Adds all elements in `ys` to set `xs` as a side effect and returns `xs` itself.| +| `xs add x` |Adds element `x` to `xs` and returns `true` if `x` was not previously contained in the set, `false` if it was.| +| **Removals:** | | +| `xs -= x` |Removes element `x` from set `xs` as a side effect and returns `xs` itself.| +| `xs -= (x, y, z)` |Removes the given elements from set `xs` as a side effect and returns `xs` itself.| +| `xs --= ys` |Removes all elements in `ys` from set `xs` as a side effect and returns `xs` itself.| +| `xs remove x` |Removes element `x` from `xs` and returns `true` if `x` was previously contained in the set, `false` if it was not.| +| `xs retain p` |Keeps only those elements in `xs` that satisfy predicate `p`.| +| `xs.clear()` |Removes all elements from `xs`.| +| **Update:** | | +| `xs(x) = b` |(or, written out, `xs.update(x, b)`). If boolean argument `b` is `true`, adds `x` to `xs`, otherwise removes `x` from `xs`.| +| **Cloning:** | | +| `xs.clone` |A new mutable set with the same elements as `xs`.| + +Just like an immutable set, a mutable set offers the `+` and `++` operations for element additions and the `-` and `--` operations for element removals. But these are less often used for mutable sets since they involve copying the set. As a more efficient alternative, mutable sets offer the update methods `+=` and `-=`. The operation `s += elem` adds `elem` to the set `s` as a side effect, and returns the mutated set as a result. Likewise, `s -= elem` removes `elem` from the set, and returns the mutated set as a result. Besides `+=` and `-=` there are also the bulk operations `++=` and `--=` which add or remove all elements of a traversable or an iterator. + +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) + +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) + +The end effect is very similar to the previous interaction; we start with a `Set(1, 2, 3)` end 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. + +Comparing the two interactions shows an important principle. You often can replace a mutable collection stored in a `val` by an immutable collection stored in a `var`, and _vice versa_. This works at least as long as there are no alias references to the collection through which one can observe whether it was updated in place or whether a new collection was created. + +Mutable sets also provide add and remove as variants of `+=` and `-=`. The difference is that `add` and `remove` return a Boolean result indicating whether the operation had an effect on the set. + +The current default implementation of a mutable set uses a hashtable to store the set's elements. The default implementation of an immutable set uses a representation that adapts to the number of elements of the set. An empty set is represented by just a singleton object. Sets of sizes up to four are represented by a single object that stores all elements as fields. Beyond that size, immutable sets are implemented as [hash tries](#hash-tries). + +A consequence of these representation choices is that, for sets of small sizes (say up to 4), immutable sets are usually more compact and also more efficient than mutable sets. So, if you expect the size of a set to be small, try making it immutable. + +Two subtraits of sets are `SortedSet` and `BitSet`. + +### Sorted Sets ### + +A [SortedSet](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html) is a set that produces its elements (using `iterator` or `foreach`) in a given ordering (which can be freely chosen at the time the set is created). The default representation of a [SortedSet](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html) is an ordered binary tree which maintains the invariant that all elements in the left subtree of a node are smaller than all elements in the right subtree. That way, a simple in order traversal can return all tree elements in increasing order. Scala's class [immutable.TreeSet](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) uses a _red-black_ tree implementation to maintain this ordering invariant and at the same time keep the tree _balanced_-- meaning that all paths from the root of the tree to a leaf have lengths that differ only by at most one element. + +To create an empty [TreeSet](http://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] = ... + +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() + +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) + +Sorted sets also support ranges of elements. For instance, the `range` method returns all elements from a starting element up to, but excluding, and 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 from "three" + res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two) + + +### 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](http://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. + diff --git a/ko/overviews/collections/strings.md b/ko/overviews/collections/strings.md new file mode 100644 index 0000000000..726f40827b --- /dev/null +++ b/ko/overviews/collections/strings.md @@ -0,0 +1,27 @@ +--- +layout: overview-large +title: Strings + +disqus: true + +partof: collections +num: 11 +language: ko +--- + +Like arrays, strings are not directly sequences, but they can be converted to them, and they also support all sequence operations on strings. Here are some examples of operations you can invoke on strings. + + scala> val str = "hello" + str: java.lang.String = hello + scala> str.reverse + res6: String = olleh + scala> str.map(_.toUpper) + res7: String = HELLO + scala> str drop 3 + res8: String = lo + scala> str slice (1, 4) + res9: String = ell + scala> val s: Seq[Char] = str + s: Seq[Char] = WrappedString(h, e, l, l, o) + +These operations are supported by two implicit conversions. The first, low-priority conversion maps a `String` to a `WrappedString`, which is a subclass of `immutable.IndexedSeq`, This conversion got applied in the last line above where a string got converted into a Seq. the other, high-priority conversion maps a string to a `StringOps` object, which adds all methods on immutable sequences to strings. This conversion was implicitly inserted in the method calls of `reverse`, `map`, `drop`, and `slice` in the example above. diff --git a/ko/overviews/collections/trait-traversable.md b/ko/overviews/collections/trait-traversable.md index a387c1718d..66df814a5e 100644 --- a/ko/overviews/collections/trait-traversable.md +++ b/ko/overviews/collections/trait-traversable.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: Traversable() 트레잇 +title: 순회가능(Traversable) 트레잇 disqus: true @@ -44,7 +44,7 @@ f가 내놓는 결과값은 `foreach`가 무시한다. ### Traversable에 정의되어 있는 연산들 ### -| 쓰는법 | 하는일 | +| 사용법 | 하는일 | | ------ | ------ | | **추상 메소드:** | | | `xs foreach f` |함수 `f`를 `xs`의 모든 원소에 적용한다.| @@ -88,7 +88,7 @@ f가 내놓는 결과값은 `foreach`가 무시한다. | `xs filter p` |`xs`의 원소 중 술어 `p`를 만족하는 원소로 이루어진 컬렉션이다.| | `xs withFilter p` |컬렉션에 필요시 계산하는 필터를 추가한다. 이 결과 컬렉션에 `map`, `flatMap`, `foreach`, `withFilter` 등이 호출되면 `xs` 중에 술어 `p`를 만족하는 원소에 대해서만 처리가 이루어진다.| | `xs filterNot p` |`xs`의 원소 중 술어 `p`를 만족하지 않는 원소로 이루어진 컬렉션이다.| -| **분할:** | +| **분할:** | | | `xs splitAt n` |`n`위치를 기준으로 `xs`를 둘로 분할한다. `(xs take n, xs drop n)` 쌍과 동일한 컬렉션 쌍을 반환한다.| | `xs span p` |`xs`를 술어 `p`를 가지고 둘로 분할하되, `(xs takeWhile p, xs.dropWhile p)`과 같은 컬렉션 쌍을 반환한다.| | `xs partition p` |`xs`를 술어 `p`를 만족하는 원소들과 만족하지 않는 원소의 두 컬렉션으로 분할한 튜플을 반환한다. `(xs filter p, xs.filterNot p)`과 같은 결과를 반환한다.| diff --git a/ko/overviews/collections/views.md b/ko/overviews/collections/views.md new file mode 100644 index 0000000000..7f894d1d5b --- /dev/null +++ b/ko/overviews/collections/views.md @@ -0,0 +1,129 @@ +--- +layout: overview-large +title: Views + +disqus: true + +partof: collections +num: 14 +language: ko +--- + +Collections have quite a few methods that construct new collections. Examples are `map`, `filter` or `++`. We call such methods transformers because they take at least one collection as their receiver object and produce another collection in their result. + +There are two principal ways to implement transformers. One is _strict_, that is a new collection with all its elements is constructed as a result of the transformer. The other is non-strict or _lazy_, that is one constructs only a proxy for the result collection, and its elements get constructed only as one demands them. + +As an example of a non-strict transformer consider the following implementation of a lazy map operation: + + def lazyMap[T, U](coll: Iterable[T], f: T => U) = new Iterable[T] { + def iterator = coll.iterator map f + } + +Note that `lazyMap` constructs a new `Iterable` without stepping through all elements of the given collection `coll`. The given function `f` is instead applied to the elements of the new collection's `iterator` as they are demanded. + +Scala collections are by default strict in all their transformers, except for `Stream`, which implements all its transformer methods lazily. However, there is a systematic way to turn every collection into a lazy one and _vice versa_, which is based on collection views. A _view_ is a special kind of collection that represents some base collection, but implements all transformers lazily. + +To go from a collection to its view, you can use the view method on the collection. If `xs` is some collection, then `xs.view` is the same collection, but with all transformers implemented lazily. To get back from a view to a strict collection, you can use the `force` method. + +Let's see an example. Say you have a vector of Ints over which you want to map two functions in succession: + + scala> val v = Vector(1 to 10: _*) + v: scala.collection.immutable.Vector[Int] = + Vector(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + scala> v map (_ + 1) map (_ * 2) + res5: scala.collection.immutable.Vector[Int] = + Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22) + +In the last statement, the expression `v map (_ + 1)` constructs a new vector which is then transformed into a third vector by the second call to `map (_ * 2)`. In many situations, constructing the intermediate result from the first call to map is a bit wasteful. In the example above, it would be faster to do a single map with the composition of the two functions `(_ + 1)` and `(_ * 2)`. If you have the two functions available in the same place you can do this by hand. But quite often, successive transformations of a data structure are done in different program modules. Fusing those transformations would then undermine modularity. A more general way to avoid the intermediate results is by turning the vector first into a view, then applying all transformations to the view, and finally forcing the view to a vector: + + scala> (v.view map (_ + 1) map (_ * 2)).force + res12: Seq[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22) + +Let's do this sequence of operations again, one by one: + + scala> val vv = v.view + vv: scala.collection.SeqView[Int,Vector[Int]] = + SeqView(1, 2, 3, 4, 5, 6, 7, 8, 9, 10) + +The application `v.view` gives you a `SeqView`, i.e. a lazily evaluated `Seq`. The type `SeqView` has two type parameters. The first, `Int`, shows the type of the view's elements. The second, `Vector[Int]` shows you the type constructor you get back when forcing the `view`. + +Applying the first `map` to the view gives: + + scala> vv map (_ + 1) + res13: scala.collection.SeqView[Int,Seq[_]] = SeqViewM(...) + +The result of the `map` is a value that prints `SeqViewM(...)`. This is in essence a wrapper that records the fact that a `map` with function `(_ + 1)` needs to be applied on the vector `v`. It does not apply that map until the view is `force`d, however. The "M" after `SeqView` is an indication that the view encapsulates a map operation. Other letters indicate other delayed operations. For instance "S" indicates a delayed `slice` operations, and "R" indicates a `reverse`. Let's now apply the second `map` to the last result. + + scala> res13 map (_ * 2) + res14: scala.collection.SeqView[Int,Seq[_]] = SeqViewMM(...) + +You now get a `SeqView` that contains two map operations, so it prints with a double "M": `SeqViewMM(...)`. Finally, forcing the last result gives: + +scala> res14.force +res15: Seq[Int] = Vector(4, 6, 8, 10, 12, 14, 16, 18, 20, 22) + +Both stored functions get applied as part of the execution of the `force` operation and a new vector is constructed. That way, no intermediate data structure is needed. + +One detail to note is that the static type of the final result is a Seq, not a Vector. Tracing the types back we see that as soon as the first delayed map was applied, the result had static type `SeqViewM[Int, Seq[_]]`. That is, the "knowledge" that the view was applied to the specific sequence type `Vector` got lost. The implementation of a view for some class requires quite a lot of code, so the Scala collection libraries provide views mostly only for general collection types, but not for specific implementations (An exception to this are arrays: Applying delayed operations on arrays will again give results with static type `Array`). + +There are two reasons why you might want to consider using views. The first is performance. You have seen that by switching a collection to a view the construction of intermediate results can be avoided. These savings can be quite important. As another example, consider the problem of finding the first palindrome in a list of words. A palindrome is a word which reads backwards the same as forwards. Here are the necessary definitions: + + def isPalindrome(x: String) = x == x.reverse + def findPalidrome(s: Seq[String]) = s find isPalindrome + +Now, assume you have a very long sequence words and you want to find a palindrome in the first million words of that sequence. Can you re-use the definition of `findPalidrome`? If course, you could write: + + findPalindrome(words take 1000000) + +This nicely separates the two aspects of taking the first million words of a sequence and finding a palindrome in it. But the downside is that it always constructs an intermediary sequence consisting of one million words, even if the first word of that sequence is already a palindrome. So potentially, 999'999 words are copied into the intermediary result without being inspected at all afterwards. Many programmers would give up here and write their own specialized version of finding palindromes in some given prefix of an argument sequence. But with views, you don't have to. Simply write: + + findPalindrome(words.view take 1000000) + +This has the same nice separation of concerns, but instead of a sequence of a million elements it will only construct a single lightweight view object. This way, you do not need to choose between performance and modularity. + +The second use case applies to views over mutable sequences. Many transformer functions on such views provide a window into the original sequence that can then be used to update selectively some elements of that sequence. To see this in an example, let's suppose you have an array `arr`: + + scala> val arr = (0 to 9).toArray + arr: Array[Int] = Array(0, 1, 2, 3, 4, 5, 6, 7, 8, 9) + +You can create a subwindow into that array by creating a slice of a view of `arr`: + + scala> val subarr = arr.view.slice(3, 6) + subarr: scala.collection.mutable.IndexedSeqView[ + Int,Array[Int]] = IndexedSeqViewS(...) + +This gives a view `subarr` which refers to the elements at positions 3 through 5 of the array `arr`. The view does not copy these elements, it just provides a reference to them. Now, assume you have a method that modifies some elements of a sequence. For instance, the following `negate` method would negate all elements of the sequence of integers it's given: + + scala> def negate(xs: collection.mutable.Seq[Int]) = + for (i <- 0 until xs.length) xs(i) = -xs(i) + negate: (xs: scala.collection.mutable.Seq[Int])Unit + +Assume now you want to negate elements at positions 3 through five of the array `arr`. Can you use `negate` for this? Using a view, this is simple: + + scala> negate(subarr) + scala> arr + res4: Array[Int] = Array(0, 1, 2, -3, -4, -5, 6, 7, 8, 9) + +What happened here is that negate changed all elements of `subarr`, which were a slice of the elements of `arr`. Again, you see that views help in keeping things modular. The code above nicely separated the question of what index range to apply a method to from the question what method to apply. + +After having seen all these nifty uses of views you might wonder why have strict collections at all? One reason is that performance comparisons do not always favor lazy over strict collections. For smaller collection sizes the added overhead of forming and applying closures in views is often greater than the gain from avoiding the intermediary data structures. A probably more important reason is that evaluation in views can be very confusing if the delayed operations have side effects. + +Here's an example which bit a few users of versions of Scala before 2.8. In these versions the Range type was lazy, so it behaved in effect like a view. People were trying to create a number of actors like this: + + + val actors = for (i <- 1 to 10) yield actor { ... } + +They were surprised that none of the actors was executing afterwards, even though the actor method should create and start an actor from the code that's enclosed in the braces following it. To explain why nothing happened, remember that the for expression above is equivalent to an application of map: + + val actors = (1 to 10) map (i => actor { ... }) + +Since previously the range produced by `(1 to 10)` behaved like a view, the result of the map was again a view. That is, no element was computed, and, consequently, no actor was created! Actors would have been created by forcing the range of the whole expression, but it's far from obvious that this is what was required to make the actors do their work. + +To avoid surprises like this, the Scala 2.8 collections library has more regular rules. All collections except streams and views are strict. The only way to go from a strict to a lazy collection is via the `view` method. The only way to go back is via `force`. So the `actors` definition above would behave as expected in Scala 2.8 in that it would create and start 10 actors. To get back the surprising previous behavior, you'd have to add an explicit `view` method call: + + val actors = for (i <- (1 to 10).view) yield actor { ... } + +In summary, views are a powerful tool to reconcile concerns of efficiency with concerns of modularity. But in order not to be entangled in aspects of delayed evaluation, you should restrict views to two scenarios. Either you apply views in purely functional code where collection transformations do not have side effects. Or you apply them over mutable collections where all modifications are done explicitly. What's best avoided is a mixture of views and operations that create new collections while also having side effects. + + + diff --git a/ko/overviews/core/collections.md b/ko/overviews/core/collections.md index 91f34cc416..ecf09c3be1 100644 --- a/ko/overviews/core/collections.md +++ b/ko/overviews/core/collections.md @@ -3,5 +3,5 @@ layout: overview overview: collections partof: collections language: ko -title: Scala コレクションライブラリ +title: Scala 컬렉션 라이브러리 --- diff --git a/overviews/collections/arrays.md b/overviews/collections/arrays.md index ff8227b3c2..73dd9875cf 100644 --- a/overviews/collections/arrays.md +++ b/overviews/collections/arrays.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 10 -languages: [ja] +languages: [ja, ko] --- [Array](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/Array.html) is a special kind of collection in Scala. On the one hand, Scala arrays correspond one-to-one to Java arrays. That is, a Scala array `Array[Int]` is represented as a Java `int[]`, an `Array[Double]` is represented as a Java `double[]` and a `Array[String]` is represented as a `Java String[]`. But at the same time, Scala arrays offer much more than their Java analogues. First, Scala arrays can be _generic_. That is, you can have an `Array[T]`, where `T` is a type parameter or abstract type. Second, Scala arrays are compatible with Scala sequences - you can pass an `Array[T]` where a `Seq[T]` is required. Finally, Scala arrays also support all sequence operations. Here's an example of this in action: diff --git a/overviews/collections/concrete-immutable-collection-classes.md b/overviews/collections/concrete-immutable-collection-classes.md index 6c3b9d4290..9969ca2af6 100644 --- a/overviews/collections/concrete-immutable-collection-classes.md +++ b/overviews/collections/concrete-immutable-collection-classes.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 8 -languages: [ja] +languages: [ja, ko] --- Scala provides many concrete immutable collection classes for you to choose from. They differ in the traits they implement (maps, sets, sequences), whether they can be infinite, and the speed of various operations. Here are some of the most common immutable collection types used in Scala. diff --git a/overviews/collections/concrete-mutable-collection-classes.md b/overviews/collections/concrete-mutable-collection-classes.md index e60459b334..66d4596c0a 100644 --- a/overviews/collections/concrete-mutable-collection-classes.md +++ b/overviews/collections/concrete-mutable-collection-classes.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 9 -languages: [ja] +languages: [ja, ko] --- You've now seen the most commonly used immutable collection classes that Scala provides in its standard library. Take a look now at the mutable collection classes. diff --git a/overviews/collections/conversions-between-java-and-scala-collections.md b/overviews/collections/conversions-between-java-and-scala-collections.md index 1517d31075..f28d5ef89a 100644 --- a/overviews/collections/conversions-between-java-and-scala-collections.md +++ b/overviews/collections/conversions-between-java-and-scala-collections.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 17 -languages: [ja] +languages: [ja, ko] --- Like Scala, Java also has a rich collections library. There are many similarities between the two. For instance, both libraries know iterators, iterables, sets, maps, and sequences. But there are also important differences. In particular, the Scala libraries put much more emphasis on immutable collections, and provide many more operations that transform a collection into a new one. diff --git a/overviews/collections/creating-collections-from-scratch.md b/overviews/collections/creating-collections-from-scratch.md index 88e29af8b9..a800378167 100644 --- a/overviews/collections/creating-collections-from-scratch.md +++ b/overviews/collections/creating-collections-from-scratch.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 16 -languages: [ja] +languages: [ja, ko] --- You have syntax `List(1, 2, 3)` to create a list of three integers and `Map('A' -> 1, 'C' -> 2)` to create a map with two bindings. This is actually a universal feature of Scala collections. You can take any collection name and follow it by a list of elements in parentheses. The result will be a new collection with the given elements. Here are some more examples: @@ -55,4 +55,4 @@ Descendants of `Seq` classes provide also other factory operations in their comp | `S.tabulate(m, n){f}` | A sequence of sequences of dimension `m×n` where the element at each index `(i, j)` is computed by `f(i, j)`. (exists also in higher dimensions). | | `S.range(start, end)` | The sequence of integers `start` ... `end-1`. | | `S.range(start, end, step)`| The sequence of integers starting with `start` and progressing by `step` increments up to, and excluding, the `end` value. | -| `S.iterate(x, n)(f)` | The sequence of length `n` with elements `x`, `f(x)`, `f(f(x))`, ... | \ No newline at end of file +| `S.iterate(x, n)(f)` | The sequence of length `n` with elements `x`, `f(x)`, `f(f(x))`, ... | diff --git a/overviews/collections/equality.md b/overviews/collections/equality.md index 8d36b26fa6..328c5f63ac 100644 --- a/overviews/collections/equality.md +++ b/overviews/collections/equality.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 13 -languages: [ja] +languages: [ja, ko] --- The collection libraries have a uniform approach to equality and hashing. The idea is, first, to divide collections into sets, maps, and sequences. Collections in different categories are always unequal. For instance, `Set(1, 2, 3)` is unequal to `List(1, 2, 3)` even though they contain the same elements. On the other hand, within the same category, collections are equal if and only if they have the same elements (for sequences: the same elements in the same order). For example, `List(1, 2, 3) == Vector(1, 2, 3)`, and `HashSet(1, 2) == TreeSet(2, 1)`. diff --git a/overviews/collections/introduction.md b/overviews/collections/introduction.md index 290ab7d337..7ac7e9bc72 100644 --- a/overviews/collections/introduction.md +++ b/overviews/collections/introduction.md @@ -93,4 +93,4 @@ as part of Scala 2.9.) This document provides an in depth discussion of the APIs of the Scala collections classes from a user perspective. They take you on -a tour of all the fundamental classes and the methods they define. \ No newline at end of file +a tour of all the fundamental classes and the methods they define. diff --git a/overviews/collections/iterators.md b/overviews/collections/iterators.md index f5b8117e9b..cf0ac3ea4a 100644 --- a/overviews/collections/iterators.md +++ b/overviews/collections/iterators.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 15 -languages: [ja] +languages: [ja, ko] --- An iterator is not a collection, but rather a way to access the elements of a collection one by one. The two basic operations on an iterator `it` are `next` and `hasNext`. A call to `it.next()` will return the next element of the iterator and advance the state of the iterator. Calling `next` again on the same iterator will then yield the element one beyond the one returned previously. If there are no more elements to return, a call to `next` will throw a `NoSuchElementException`. You can find out whether there are more elements to return using [Iterator](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/Iterator.html)'s `hasNext` method. diff --git a/overviews/collections/maps.md b/overviews/collections/maps.md index 24d53a937b..e917859493 100644 --- a/overviews/collections/maps.md +++ b/overviews/collections/maps.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 7 -languages: [ja] +languages: [ja, ko] --- A [Map](http://www.scala-lang.org/api/current/scala/collection/Map.html) is an [Iterable](http://www.scala-lang.org/api/current/scala/collection/Iterable.html) consisting of pairs of keys and values (also named _mappings_ or _associations_). Scala's [Predef](http://www.scala-lang.org/api/current/scala/Predef$.html) class offers an implicit conversion that lets you write `key -> value` as an alternate syntax for the pair `(key, value)`. For instance `Map("x" -> 24, "y" -> 25, "z" -> 26)` means exactly the same as `Map(("x", 24), ("y", 25), ("z", 26))`, but reads better. diff --git a/overviews/collections/migrating-from-scala-27.md b/overviews/collections/migrating-from-scala-27.md index b37fd5e2c5..12c4d6c76b 100644 --- a/overviews/collections/migrating-from-scala-27.md +++ b/overviews/collections/migrating-from-scala-27.md @@ -7,7 +7,7 @@ disqus: true partof: collections num: 18 outof: 18 -languages: [ja] +languages: [ja, ko] --- Porting your existing Scala applications to use the new collections should be almost automatic. There are only a couple of possible issues to take care of. diff --git a/overviews/collections/overview.md b/overviews/collections/overview.md index 64517c8d42..b2a372a202 100644 --- a/overviews/collections/overview.md +++ b/overviews/collections/overview.md @@ -139,4 +139,4 @@ This behavior which is implemented everywhere in the collections libraries is ca Most of the classes in the collections hierarchy exist in three variants: root, mutable, and immutable. The only exception is the Buffer trait which only exists as a mutable collection. -In the following, we will review these classes one by one. \ No newline at end of file +In the following, we will review these classes one by one. diff --git a/overviews/collections/performance-characteristics.md b/overviews/collections/performance-characteristics.md index 057a5b8155..3e37b00bd1 100644 --- a/overviews/collections/performance-characteristics.md +++ b/overviews/collections/performance-characteristics.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 12 -languages: [ja] +languages: [ja, ko] --- The previous explanations have made it clear that different collection types have different performance characteristics. That's often the primary reason for picking one collection type over another. You can see the performance characteristics of some common operations on collections summarized in the following two tables. diff --git a/overviews/collections/seqs.md b/overviews/collections/seqs.md index 0187b91106..4c32c906eb 100644 --- a/overviews/collections/seqs.md +++ b/overviews/collections/seqs.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 5 -languages: [ja] +languages: [ja, ko] --- The [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) trait represents sequences. A sequence is a kind of iterable that has a `length` and whose elements have fixed index positions, starting from `0`. diff --git a/overviews/collections/sets.md b/overviews/collections/sets.md index 6d65274f32..5db970bfca 100644 --- a/overviews/collections/sets.md +++ b/overviews/collections/sets.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 6 -languages: [ja] +languages: [ja, ko] --- `Set`s are `Iterable`s that contain no duplicate elements. The operations on sets are summarized in the following table for general sets and in the table after that for mutable sets. They fall into the following categories: diff --git a/overviews/collections/strings.md b/overviews/collections/strings.md index 68a57ecc3b..61158306e1 100644 --- a/overviews/collections/strings.md +++ b/overviews/collections/strings.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 11 -languages: [ja] +languages: [ja, ko] --- Like arrays, strings are not directly sequences, but they can be converted to them, and they also support all sequence operations on strings. Here are some examples of operations you can invoke on strings. @@ -24,4 +24,4 @@ Like arrays, strings are not directly sequences, but they can be converted to th scala> val s: Seq[Char] = str s: Seq[Char] = WrappedString(h, e, l, l, o) -These operations are supported by two implicit conversions. The first, low-priority conversion maps a `String` to a `WrappedString`, which is a subclass of `immutable.IndexedSeq`, This conversion got applied in the last line above where a string got converted into a Seq. the other, high-priority conversion maps a string to a `StringOps` object, which adds all methods on immutable sequences to strings. This conversion was implicitly inserted in the method calls of `reverse`, `map`, `drop`, and `slice` in the example above. \ No newline at end of file +These operations are supported by two implicit conversions. The first, low-priority conversion maps a `String` to a `WrappedString`, which is a subclass of `immutable.IndexedSeq`, This conversion got applied in the last line above where a string got converted into a Seq. the other, high-priority conversion maps a string to a `StringOps` object, which adds all methods on immutable sequences to strings. This conversion was implicitly inserted in the method calls of `reverse`, `map`, `drop`, and `slice` in the example above. diff --git a/overviews/collections/views.md b/overviews/collections/views.md index 8304d0419d..a43606d6c9 100644 --- a/overviews/collections/views.md +++ b/overviews/collections/views.md @@ -6,7 +6,7 @@ disqus: true partof: collections num: 14 -languages: [ja] +languages: [ja, ko] --- Collections have quite a few methods that construct new collections. Examples are `map`, `filter` or `++`. We call such methods transformers because they take at least one collection as their receiver object and produce another collection in their result. From 2b9ef21933acfcf52901dea023af0efb05898982 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Wed, 26 Jun 2013 15:20:43 +1000 Subject: [PATCH 10/17] end of 1st translation of seqs.md --- ko/overviews/collections/seqs.md | 157 +++++++++--------- ko/overviews/collections/trait-iterable.md | 8 +- ko/overviews/collections/trait-traversable.md | 12 +- 3 files changed, 89 insertions(+), 88 deletions(-) diff --git a/ko/overviews/collections/seqs.md b/ko/overviews/collections/seqs.md index a58da9c782..815832bc2c 100644 --- a/ko/overviews/collections/seqs.md +++ b/ko/overviews/collections/seqs.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: The sequence traits Seq, IndexedSeq, and LinearSeq +title: 열 트레잇 Seq, IndexedSeq, LinearSeq disqus: true @@ -9,93 +9,94 @@ num: 5 language: ko --- -The [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) trait represents sequences. A sequence is a kind of iterable that has a `length` and whose elements have fixed index positions, starting from `0`. +[Seq(열)](http://www.scala-lang.org/api/current/scala/collection/Seq.html) 트레잇은 순서가 있는 열을 표현한다. +열이란 `length`가 있고 원소들이 고정된 첨자로 표현되는 위치를 가지고 있는 반복가능한 객체를 말한다. 첨자는 `0`부터 시작한다. -The operations on sequences, summarized in the table below, fall into the following categories: +표에 열이 제공하는 연산이 정리되어 있다. 각 연산은 다음과 같이 분류할 수 있다. -* **Indexing and length** operations `apply`, `isDefinedAt`, `length`, `indices`, and `lengthCompare`. For a `Seq`, the `apply` operation means indexing; hence a sequence of type `Seq[T]` is a partial function that takes an `Int` argument (an index) and which yields a sequence element of type `T`. In other words `Seq[T]` extends `PartialFunction[Int, T]`. The elements of a sequence are indexed from zero up to the `length` of the sequence minus one. The `length` method on sequences is an alias of the `size` method of general collections. The `lengthCompare` method allows you to compare the lengths of two sequences even if one of the sequences has infinite length. -* **Index search operations** `indexOf`, `lastIndexOf`, `indexofSlice`, `lastIndexOfSlice`, `indexWhere`, `lastIndexWhere`, `segmentLength`, `prefixLength`, which return the index of an element equal to a given value or matching some predicate. -* **Addition operations** `+:`, `:+`, `padTo`, which return new sequences obtained by adding elements at the front or the end of a sequence. -* **Update operations** `updated`, `patch`, which return a new sequence obtained by replacing some elements of the original sequence. -* **Sorting operations** `sorted`, `sortWith`, `sortBy`, which sort sequence elements according to various criteria. -* **Reversal operations** `reverse`, `reverseIterator`, `reverseMap`, which yield or process sequence elements in reverse order. -* **Comparisons** `startsWith`, `endsWith`, `contains`, `containsSlice`, `corresponds`, which relate two sequences or search an element in a sequence. -* **Multiset** operations `intersect`, `diff`, `union`, `distinct`, which perform set-like operations on the elements of two sequences or remove duplicates. +* **참조와 길이** 연산으로 `apply`, `isDefinedAt`, `length`, `indices`, `lengthCompare`가 있다. `Seq`에 있어, `apply` 연산은 첨자에 의해 원소를 참조하는 것이다. 따라서 `Seq[T]` 타입의 열은 `Int` 인자(첨자)를 받아서 열의 원소인 타입 `T` 객체를 반환하는 부분함수로 볼 수 있다. 즉, `Seq[T]`는 `PartialFunction[Int, T]`를 구현한다. 열의 원소에는 0부터 열의 `length`-1 까지 첨자가 부여된다. `length` 메소드는 일반적인 컬렉션의 `size`에 대한 별명이다. `lengthCompare` 메소드는 두 열(무한열인 경우도 포함됨)의 길이를 비교해준다. +* **첨자 검색 연산** `indexOf`, `lastIndexOf`, `indexofSlice`, `lastIndexOfSlice`, `indexWhere`, `lastIndexWhere`, `segmentLength`, `prefixLength`는 주어진 값과 같거나 주어진 술어와 일치하는 원소의 첨자를 반환한다. +* **덧붙임** 연산 `+:`, `:+`, `padTo`는 열의 맨 앞이나 뒤에 원소를 추가해 만들어지는 새 열을 반환한다. +* **갱신** 연산 `updated`, `patch`는 원래의 열의 일부 원소를 다른 값으로 대치한 새 열을 반환한다. +* **정렬** 연산 `sorted`, `sortWith`, `sortBy`는 여러 기준에 의해 열을 정렬한다. +* **반전** 연산 `reverse`, `reverseIterator`, `reverseMap`은 열의 원소를 역순으로 처리하거나 내어 놓는다. +* **비교** `startsWith`, `endsWith`, `contains`, `containsSlice`, `corresponds`는 두 열을 연관짓거나 열 안에서 원소를 찾는다. +* **중복집합(Multiset)** 연산인 `intersect`, `diff`, `union`, `distinct`는 두 열의 원소에 대해 집합과 비슷한 연산을 수행하거나, 중복을 제거한다. -If a sequence is mutable, it offers in addition a side-effecting `update` method, which lets sequence elements be updated. As always in Scala, syntax like `seq(idx) = elem` is just a shorthand for `seq.update(idx, elem)`, so `update` gives convenient assignment syntax for free. Note the difference between `update` and `updated`. `update` changes a sequence element in place, and is only available for mutable sequences. `updated` is available for all sequences and always returns a new sequence instead of modifying the original. +열이 변경 가능하다면 추가로 부작용을 사용하는 `update` 메소드를 제공한다. 이를 사용해 열의 원소를 변경할 수 있다. 스칼라에서 항상 그렇듯이 `seq(idx) = elem`는 단지 `seq.update(idx, elem)`를 짧게 쓴 것 뿐이다. 따라서 `update`를 정의하면 공짜로 대입 문법을 사용할 수 있게 된다. `update`와 `updated`가 다름에 유의하라. `update`는 어떤 열의 원소를 그 자리(새 열을 만들지 않고 열 자체를 갱신)에서 변경하며 변경 가능한 열에서만 사용할 수 있다. `updated`는 모든 열에서 사용 가능하며 항상 원래의 열은 그대로 두고 새로운 열을 반환한다. -### Operations in Class Seq ### +### Seq 클래스의 연산 ### -| WHAT IT IS | WHAT IT DOES | +| 사용법 | 하는일 | | ------ | ------ | -| **Indexing and Length:** | | -| `xs(i)` |(or, written out, `xs apply i`). The element of `xs` at index `i`.| -| `xs isDefinedAt i` |Tests whether `i` is contained in `xs.indices`.| -| `xs.length` |The length of the sequence (same as `size`).| -| `xs.lengthCompare ys` |Returns `-1` if `xs` is shorter than `ys`, `+1` if it is longer, and `0` is they have the same length. Works even if one if the sequences is infinite.| -| `xs.indices` |The index range of `xs`, extending from `0` to `xs.length - 1`.| -| **Index Search:** | | -| `xs indexOf x` |The index of the first element in `xs` equal to `x` (several variants exist).| -| `xs lastIndexOf x` |The index of the last element in `xs` equal to `x` (several variants exist).| -| `xs indexOfSlice ys` |The first index of `xs` such that successive elements starting from that index form the sequence `ys`.| -| `xs lastIndexOfSlice ys` |The last index of `xs` such that successive elements starting from that index form the sequence `ys`.| -| `xs indexWhere p` |The index of the first element in xs that satisfies `p` (several variants exist).| -| `xs segmentLength (p, i)`|The length of the longest uninterrupted segment of elements in `xs`, starting with `xs(i)`, that all satisfy the predicate `p`.| -| `xs prefixLength p` |The length of the longest prefix of elements in `xs` that all satisfy the predicate `p`.| -| **Additions:** | | -| `x +: xs` |A new sequence that consists of `x` prepended to `xs`.| -| `xs :+ x` |A new sequence that consists of `x` appended to `xs`.| -| `xs padTo (len, x)` |The sequence resulting from appending the value `x` to `xs` until length `len` is reached.| -| **Updates:** | | -| `xs patch (i, ys, r)` |The sequence resulting from replacing `r` elements of `xs` starting with `i` by the patch `ys`.| -| `xs updated (i, x)` |A copy of `xs` with the element at index `i` replaced by `x`.| -| `xs(i) = x` |(or, written out, `xs.update(i, x)`, only available for `mutable.Seq`s). Changes the element of `xs` at index `i` to `x`.| -| **Sorting:** | | -| `xs.sorted` |A new sequence obtained by sorting the elements of `xs` using the standard ordering of the element type of `xs`.| -| `xs sortWith lt` |A new sequence obtained by sorting the elements of `xs` using `lt` as comparison operation.| -| `xs sortBy f` |A new sequence obtained by sorting the elements of `xs`. Comparison between two elements proceeds by mapping the function `f` over both and comparing the results.| -| **Reversals:** | | -| `xs.reverse` |A sequence with the elements of `xs` in reverse order.| -| `xs.reverseIterator` |An iterator yielding all the elements of `xs` in reverse order.| -| `xs reverseMap f` |A sequence obtained by mapping `f` over the elements of `xs` in reverse order.| -| **Comparisons:** | | -| `xs startsWith ys` |Tests whether `xs` starts with sequence `ys` (several variants exist).| -| `xs endsWith ys` |Tests whether `xs` ends with sequence `ys` (several variants exist).| -| `xs contains x` |Tests whether `xs` has an element equal to `x`.| -| `xs containsSlice ys` |Tests whether `xs` has a contiguous subsequence equal to `ys`.| -| `(xs corresponds ys)(p)` |Tests whether corresponding elements of `xs` and `ys` satisfy the binary predicate `p`.| -| **Multiset Operations:** | | -| `xs intersect ys` |The multi-set intersection of sequences `xs` and `ys` that preserves the order of elements in `xs`.| -| `xs diff ys` |The multi-set difference of sequences `xs` and `ys` that preserves the order of elements in `xs`.| -| `xs union ys` |Multiset union; same as `xs ++ ys`.| -| `xs.distinct` |A subsequence of `xs` that contains no duplicated element.| +| **참조와 길이:** | | +| `xs(i)` |(명시적으로 `xs apply i`라고 쓸수도 있음)`xs`에서 첨자 `i` 번째에 있는 원소를 반환한다.| +| `xs isDefinedAt i` |`i`가 `xs.indices` 안에 있는지 여부를 반환한다.| +| `xs.length` |열의 길이를 반환한다(`size`와 동일).| +| `xs.lengthCompare ys` |`xs`가 `ys`보다 짧으면 `-1`, 길면 `+1`, 같은 길이이면 `0`을 반환한다. 길이가 무한한 경우라도 동작한다(현재는 인자로 정수를 받아 열의 길이와 비교하는 것으로 바뀜)| +| `xs.indices` |`xs`의 첨자 범위를 반환한다. `0`부터 `xs.length - 1`까지 범위를 반환한다.| +| **첨자 검색:** | | +| `xs indexOf x` |`xs`에서 `x`와 같은 첫번째 원소의 첨자를 반환한다(몇 가지 변형이 존재한다).| +| `xs lastIndexOf x` |`xs`에서 `x`와 같은 마지막 원소의 첨자를 반환한다(몇 가지 변형이 존재한다).| +| `xs indexOfSlice ys` |`xs`에서 해당 위치에서부터 시작하는 슬라이스(slice,부분열)이 `ys`와 같은 첫번째 위치를 반환한다.| +| `xs lastIndexOfSlice ys` |`xs`에서 해당 위치에서부터 시작하는 슬라이스(slice,부분열)이 `ys`와 같은 마지막 위치를 반환한다.| +| `xs indexWhere p` |`xs`에서 `p`를 만족하는 첫번째 원소의 첨자를 반환한다(몇 가지 변형이 존재한다).| +| `xs segmentLength (p, i)`|`xs(i)`부터 시작해서 연속적으로 `p`를 만족하는 가장 긴 열의 길이를 구한다.| +| `xs prefixLength p` |`xs`의 맨 앞에서부터 시작해서 연속적으로 `p`를 만족하는 가장 긴 열의 길이를 구한다.| +| **덧붙임:** | | +| `x +: xs` |`xs`의 앞에 `x`를 붙여서 만들어진 새 열을 반환한다.| +| `xs :+ x` |`xs`의 뒤에 `x`를 붙여서 만들어진 새 열을 반환한다.| +| `xs padTo (len, x)` |`xs`의 뒤에 `x`를 전체 길이가 `len`이 될 때까지 붙여서 만들어진 새 열을 반환한다.| +| **갱신:** | | +| `xs patch (i, ys, r)` |`xs`에서 첨자 `i` 번째부터 `r`개 만큼의 원소를 `ys`의 원소로 바꿔치기 해서 얻은 새 열을 반환한다.| +| `xs updated (i, x)` |`xs`에서 첨자 `i`에 있는 원소를 `x`로 바꾼 새 열을 반환한다.| +| `xs(i) = x` |(또는 명시적으로 `xs.update(i, x)`라고 쓴다. `mutable.Seq`에서만 사용 가능하다). `xs`의 `i` 번째 원소를 `x`로 변경한다.| +| **정렬:** | | +| `xs.sorted` |`xs`의 원소를 원소 타입의 표준적인 순서를 사용해 정렬한 결과 열을 반환한다.| +| `xs sortWith lt` |`xs`의 원소를 `lt`를 비교 연산으로 사용해 정렬한 결과 열을 반환한다.| +| `xs sortBy f` |`xs`의 원소를 정렬한 결과 열을 반환한다. 비교시 두 원소에 각각 `f`를 적용한 다음 그 결과값을 서로 비교한다.| +| **반전:** | | +| `xs.reverse` |`xs`의 원소를 역순으로 나열한 열을 반환한다.| +| `xs.reverseIterator` |`xs`의 원소를 역순으로 내어 놓는 이터레이터이다.| +| `xs reverseMap f` |`xs`의 원소를 역순으로 순회하면서 `f`를 적용해 나온 결과 값으로 이루어진 열을 반환한다.| +| **비교:** | | +| `xs startsWith ys` |`xs`가 열 `ys`로 시작하는지 여부를 반환한다(몇 가지 변형이 존재한다).| +| `xs endsWith ys` |`xs`가 열 `ys`로 끝나는지 여부를 반환한다(몇 가지 변형이 존재한다).| +| `xs contains x` |`xs`에 `x`원소가 존재하는지 여부를 반환한다.| +| `xs containsSlice ys` |`xs`에 `ys`과 같은 부분열이 존재하는지 여부를 반환한다.| +| `(xs corresponds ys)(p)` |`xs`와 `ys`에서 서로 대응하는 원소가 술어 `p`를 만족하는지 여부를 반환한다.| +| **중복집합 연산:** | | +| `xs intersect ys` |`xs`와 `ys`의 중복 교집합 연산 결과인 열을 반환한다. `xs`에서의 원소 순서를 유지한다.| +| `xs diff ys` |`xs`와 `ys`의 중복 차집합 연산 결과인 열을 반한한다. `xs`에서의 원소 순서를 유지한다.| +| `xs union ys` |중복 합집합 연산 결과인 열을 반환한다. `xs ++ ys`와 같다.| +| `xs.distinct` |`xs`에서 중복을 제거한(중복된 원소는 하나만 남기고, 하나만 있는 원소는 그대로 둔) 부분열을 반환한다.| -Trait [Seq](http://www.scala-lang.org/api/current/scala/collection/Seq.html) has two subtraits [LinearSeq](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html), and [IndexedSeq](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html). These do not add any new operations, but each offers different performance characteristics: A linear sequence has efficient `head` and `tail` operations, whereas an indexed sequence has efficient `apply`, `length`, and (if mutable) `update` operations. Frequently used linear sequences are `scala.collection.immutable.List` and `scala.collection.immutable.Stream`. Frequently used indexed sequences are `scala.Array` and `scala.collection.mutable.ArrayBuffer`. The `Vector` class provides an interesting compromise between indexed and linear access. It has both effectively constant time indexing overhead and constant time linear access overhead. Because of this, vectors are a good foundation for mixed access patterns where both indexed and linear accesses are used. You'll learn more on vectors [later](#vectors). +트레잇 [열(Seq)](http://www.scala-lang.org/api/current/scala/collection/Seq.html)에는 [선형열(LinearSeq)](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html)과 [첨자열(IndexedSeq)](http://www.scala-lang.org/api/current/scala/collection/IndexedSeq.html) 두 하위 트레잇이 있다. 이 두 트레잇에 새로 추가된 메소드는 없지만, 성능상 차이가 나는 특성을 각각 제공한다. 선형 열은 효율적인 `head`와 `tail` 연산이 제공되는 반면, 첨자열은 효율적인 `apply`, `length`, 그리고 (변경 가능한 경우) `update` 연산을 제공한다. 자주 사용되는 선형 열로는 `scala.collection.immutable.List`, `scala.collection.immutable.Stream`이 있다. 자주 사용되는 첨자열로는 `scala.Array`와 `scala.collection.mutable.ArrayBuffer`를 들 수 있다. `Vector(벡터)` 클래스는 첨자열과 선형열 사이에서 흥미로운 절충안을 제공한다. 벡터는 상수 시간에 첨자에 의한 참조가 가능하며 선형 억세스도 상수시간에 가능하다. 이로 인해 첨자 참조와 선형 억세스가 동시에 사용되는 억세스 패턴인 경우 벡터가 좋은 선택일 수 있다. 벡터에 대해서는 [나중에](#vectors) 다룰 것이다. -### Buffers ### +### 버퍼 ### -An important sub-category of mutable sequences is `Buffer`s. They allow not only updates of existing elements but also element insertions, element removals, and efficient additions of new elements at the end of the buffer. The principal new methods supported by a buffer are `+=` and `++=` for element addition at the end, `+=:` and `++=:` for addition at the front, `insert` and `insertAll` for element insertions, as well as `remove` and `-=` for element removal. These operations are summarized in the following table. +변경 가능한 열의 하위 범주 중 중요한 것은 `Buffer(버퍼)`이다. 버퍼는 기존 원소를 변경할 수 있을 뿐 아니라, 원소를 추가, 삭제 하거나, 버퍼의 마지막에 효율적으로 원소를 추가할 수 있다. 버퍼가 추가로 지원하는 주요 메소드로는 원소를 끝에 추가하기 위한 `+=`, `++=`, 원소를 앞에 추가하기 위한 `+=:` and `++=:`, 원소를 삽입하기 위한 `insert`와 `insertAll`, 그리고 원소를 제거하기 위한 `remove`, `-=`가 있다. 이 연산을 아래 표에 정리해 두었다. -Two often used implementations of buffers are `ListBuffer` and `ArrayBuffer`. As the name implies, a `ListBuffer` is backed by a `List`, and supports efficient conversion of its elements to a `List`, whereas an `ArrayBuffer` is backed by an array, and can be quickly converted into one. +자주 사용되는 버퍼 구현을 두 가지 들자면 `ListBuffer`와 `ArrayBuffer`가 있다. 이름이 암시하든 `ListBuffer`는 `List`에 의해 뒷받침되며 원소를 효율적으로 `List`로 변환할 수 있다. 반면 `ArrayBuffer`는 배열에 의해 뒷받침되며 배열로 쉽게 변환 가능하다. -#### Operations in Class Buffer #### +#### 버퍼 클래스의 연산 #### -| WHAT IT IS | WHAT IT DOES| +| 사용법 | 하는 일 | | ------ | ------ | -| **Additions:** | | -| `buf += x` |Appends element `x` to buffer, and returns `buf` itself as result.| -| `buf += (x, y, z)` |Appends given elements to buffer.| -| `buf ++= xs` |Appends all elements in `xs` to buffer.| -| `x +=: buf` |Prepends element `x` to buffer.| -| `xs ++=: buf` |Prepends all elements in `xs` to buffer.| -| `buf insert (i, x)` |Inserts element `x` at index `i` in buffer.| -| `buf insertAll (i, xs)` |Inserts all elements in `xs` at index `i` in buffer.| -| **Removals:** | | -| `buf -= x` |Removes element `x` from buffer.| -| `buf remove i` |Removes element at index `i` from buffer.| -| `buf remove (i, n)` |Removes `n` elements starting at index `i` from buffer.| -| `buf trimStart n` |Removes first `n` elements from buffer.| -| `buf trimEnd n` |Removes last `n` elements from buffer.| -| `buf.clear()` |Removes all elements from buffer.| -| **Cloning:** | | -| `buf.clone` |A new buffer with the same elements as `buf`.| +| **추가:** | | +| `buf += x` |원소 `x`를 버퍼의 끝에 추가하고 `buf` 자신을 반환한다.| +| `buf += (x, y, z)` |여러 원소를 버퍼의 끝에 추가한다.| +| `buf ++= xs` |`xs`의 모든 원소를 버퍼의 끝에 추가한다.| +| `x +=: buf` |`x`를 버퍼의 앞에 추가한다.| +| `xs ++=: buf` |`xs`의 모든 원소를 버퍼의 앞에 추가한다.| +| `buf insert (i, x)` |원소 `x`를 버퍼의 첨자 `i` 번째 원소 앞에 삽입한다.| +| `buf insertAll (i, xs)` |`xs`의 모든 원소를 버퍼의 첨자 `i`번째 원소 앞에 삽입한다.| +| **제거:** | | +| `buf -= x` |원소 `x`를 버퍼에서 제거한다. (중복이 있는 경우 맨 첫 `x`만을 제거한다.)| +| `buf remove i` |첨자 `i` 번째에 이는 원소를 버퍼에서 제거한다.| +| `buf remove (i, n)` |첨자 `i`번째에 있는 원소 부터 `n`개의 원소를 버퍼에서 제거한다.| +| `buf trimStart n` |처음 `n` 개의 원소를 버퍼에서 제거한다.| +| `buf trimEnd n` |마지막 `n` 개의 원소를 버퍼에서 제거한다.| +| `buf.clear()` |모든 원소를 버퍼에서 제거한다.| +| **복사:** | | +| `buf.clone` |`buf` 같은 원소를 포함하고 있는 새로운 버퍼를 만든다.| diff --git a/ko/overviews/collections/trait-iterable.md b/ko/overviews/collections/trait-iterable.md index 1122bb9d79..77e949c15e 100644 --- a/ko/overviews/collections/trait-iterable.md +++ b/ko/overviews/collections/trait-iterable.md @@ -18,7 +18,7 @@ language: ko `Iterable`의 하위 클래스 중 상당수는 이 `foreach` 표준 구현을 재정의(override)하고 있다. 왜냐하면 더 효율적인 구현이 가능하기 때문이다. `foreach`가 `Traversable`의 모든 메소드 구현에 사용됨을 기억하라. 따라서, 성능을 진지하게 고려해야 한다. -`Iterable`에는 반복자를 반환하는 메소드가 두 개 더 있다. 이들은 각각 `grouped`와 `sliding`이다. 그러나 이 반복자들은 원래의 컬렉션의 한 원소만을 반환하는 것이 아니고, 전체 원소의 부분적인 순서열을 반환한다. 각 메소드는 이런 부분 순서열의 최대 크기를 인자로 받는다. `grouped` 메소드는 원소를 일정한 "덩어리(chunked)" 단위로 반환하는 반면, `sliding`은 원소에 대한 "미닫이 창(sliding window)"을 반환한다. 아래 REPL 수행 예를 보면 이 둘 사이의 차이를 명확히 알 수 있을 것이다. +`Iterable`에는 반복자를 반환하는 메소드가 두 개 더 있다. 이들은 각각 `grouped`와 `sliding`이다. 그러나 이 반복자들은 원래의 컬렉션의 한 원소만을 반환하는 것이 아니고, 전체 원소의 부분 열을 반환한다. 각 메소드는 이런 부분 열의 최대 크기를 인자로 받는다. `grouped` 메소드는 원소를 일정한 "덩어리(chunked)" 단위로 반환하는 반면, `sliding`은 원소에 대한 "미닫이 창(sliding window)"을 반환한다. 아래 REPL 수행 예를 보면 이 둘 사이의 차이를 명확히 알 수 있을 것이다. scala> val xs = List(1, 2, 3, 4, 5) xs: List[Int] = List(1, 2, 3, 4, 5) @@ -52,15 +52,15 @@ language: ko | `xs takeRight n` |`xs`의 마지막 `n`개의 원소로 이루어진 컬렉션을 반환한다(순서가 없는 컬렉션이라면 임의의 `n`개를 반환한다).| | `xs dropRight n` |`xs takeRight n`의 결과를 제외한 나머지 컬렉션을 반환한다.| | **묶기(zip):** | | -| `xs zip ys` |`xs`와 `ys`에서 같은 위치에 있는 원소를 각각 가져와 만든 튜플로 이루어진 컬렉션을 반환한다. (길이가 다르다면 짧은쪽 리스트의 원소 갯수 만큼만 반환한다.) | +| `xs zip ys` |`xs`와 `ys`에서 같은 위치에 있는 원소를 각각 가져와 만든 튜플로 이루어진 컬렉션을 반환한다. 길이가 다르다면 짧은 컬렉션의 원소 갯수 만큼만 반환한다. | | `xs zipAll (ys, x, y)` |`zip`과 같지만, 길이가 다른 경우 `x`나 `y`를 더 짧은쪽 리스트의 원소가 모자란 경우 대신 사용한다.| | `xs.zipWithIndex` |`xs`의 원소와 그 위치를 나타내는 첨자를 튜플로 만든 컬렉션을 반환한다.| | **비교:** | | | `xs sameElements ys` |`xs`와 `ys`가 같은 순서로 같은 원소를 포함하고 있는지 비교한다.| -상속 계층에서 Iterable의 하위에는 다음 세 트레잇이 있다. [순서열(Seq)](http://www.scala-lang.org/docu/files/collections-api/collections_5.html), [집합(Set)](http://www.scala-lang.org/docu/files/collections-api/collections_7.html), [맵(Map)](http://www.scala-lang.org/docu/files/collections-api/collections_10.html)가 그것이다. 이 세 트레잇의 공통점은 모두 다 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html) 트레잇의 `apply`와 `isDefinedAt` 메소드를 정의하고 있다는 것이다. 하지만, 각 트레잇이 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html)를 구현한 방법은 각각 다르다. +상속 계층에서 Iterable의 하위에는 다음 세 트레잇이 있다. [열(Seq)](http://www.scala-lang.org/docu/files/collections-api/collections_5.html), [집합(Set)](http://www.scala-lang.org/docu/files/collections-api/collections_7.html), [맵(Map)](http://www.scala-lang.org/docu/files/collections-api/collections_10.html)이 그것이다. 이 세 트레잇의 공통점은 모두 다 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html) 트레잇의 `apply`와 `isDefinedAt` 메소드를 정의하고 있다는 것이다. 하지만, 각 트레잇이 [부분함수(PartialFunction)](http://www.scala-lang.org/api/current/scala/PartialFunction.html)를 구현한 방법은 각각 다르다. -순서열에서 `apply`는 위치에 따라 첨자를 부여한다. 이는 첫번째 원소의 첨자 `0`부터 시작한다. 따라서 `Seq(1, 2, 3)(1)`은 `2`를 반환한다. 집합의 경우 `apply`는 포함관계 검사이다. 예를 들어 `Set('a', 'b', 'c')('b')`은 `true`를, `Set()('a')`는 `false`를 반환한다. 마지막으로 맵의 경우 `apply`는 선택(검색)이다. 예를 들어 `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')`의 결과는 `10`이다. +열에서 `apply`는 위치에 따라 첨자를 부여한다. 첨자는 첫번째 원소 `0` 부터 시작한다. 따라서 `Seq(1, 2, 3)(1)`은 `2`를 반환한다. 집합의 경우 `apply`는 포함관계 검사이다. 예를 들어 `Set('a', 'b', 'c')('b')`은 `true`를, `Set()('a')`는 `false`를 반환한다. 마지막으로 맵의 경우 `apply`는 선택(검색)이다. 예를 들어 `Map('a' -> 1, 'b' -> 10, 'c' -> 100)('b')`의 결과는 `10`이다. 다음 글에서는 위 세 컬렉션을 더 자세히 살펴볼 것이다. diff --git a/ko/overviews/collections/trait-traversable.md b/ko/overviews/collections/trait-traversable.md index 66df814a5e..aca7d5b83f 100644 --- a/ko/overviews/collections/trait-traversable.md +++ b/ko/overviews/collections/trait-traversable.md @@ -17,7 +17,7 @@ language: ko `Traversable`을 구현하는 컬렉션 클래스는 단지 이 메소드만 정의하면 된다. 다른 메소드는 자동으로 `Traversable`에서 상속된다. -`foreach` 메소드는 컬렉션의 모든 원소를 방문하면서 주어진 연산 f를 각 원소에 +`foreach` 메소드는 컬렉션의 모든 원소를 차례로 방문하면서 주어진 연산 f를 각 원소에 적용한다. 이 연산 f의 타입은 `Elem => U`로 `Elem`은 컬렉션의 원소의 타입이며, `U`는 임의의 결과 타입이다. `f`는 부작용을 위해 호출된다. 따라서 f가 내놓는 결과값은 `foreach`가 무시한다. @@ -25,9 +25,9 @@ f가 내놓는 결과값은 `foreach`가 무시한다. `Traversable`에는 여러 구체적 메소드가 정의되어 있다. 이들은 아래 표에 나열되어 있다. 각 메소드들은 다음과 같은 분류에 속한다. -* **병합** 연산 `++`는 두 방문가능한 객체를 함께 이어붙이거나, 한 반복자의 모든 원소를 다른 방문가능 객체에 추가한다. +* **병합** 연산 `++`는 두 방문가능한 객체를 함께 이어붙이거나, 어떤 방문가능 객체에 다른 반복자의 모든 원소를 추가한다. * **맵** 연산인 `map`, `flatMap`, `collect`는 인자로 넘겨진 함수를 컬렉션 원소에 적용한 결과로 이루어진 새 컬렉션을 만들어낸다. -* **변환** 연산인 `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap` 등은 `Traversable` +* **변환** 연산인 `toArray`, `toList`, `toIterable`, `toSeq`, `toIndexedSeq`, `toStream`, `toSet`, `toMap`은 `Traversable` 컬렉션을 더 구체적인 데이터 구조로 변환한다. 런타임에 수신자가 이미 변환 결과 컬렉션 타입이었다면, 각 변환 메소드는 수신자를 그대로 반환한다. 예를 들어 리스트에 `toList`를 적용하면 그 리스트 자신이 반환된다. * **복사** 연산으로 `copyToBuffer`와 `copyToArray`가 있다. 이름이 말하는데로 각각 컬렉션 원소를 버퍼나 배열에 복사한다. * **크기 정보** 연산 `isEmpty`, `nonEmpty`, `size`, `hasDefiniteSize`: 순회가능한 컬렉션은 유한할 수도 있고, 무한할 수도 있다. @@ -42,7 +42,7 @@ f가 내놓는 결과값은 `foreach`가 무시한다. * **문자열** 연산 `mkString`, `addString`, `stringPrefix`는 컬렉션을 문자열로 바꾸는 여러가지 방법을 제공한다. * **뷰** 연산은 `view` 메소드를 오버로딩한 두 메소드이다. 뷰는 지연 계산될 수 있는 컬렉션이다. 뷰에 대해서는 [나중에](#Views) 다룰 것이다. -### Traversable에 정의되어 있는 연산들 ### +### Traversable 클래스의 연산 ### | 사용법 | 하는일 | | ------ | ------ | @@ -58,8 +58,8 @@ f가 내놓는 결과값은 `foreach`가 무시한다. | `xs.toArray` |컬렉션을 배열(Array)로 변환한다.| | `xs.toList` |컬렉션을 리스트(List)로 변환한다.| | `xs.toIterable` |컬렉션을 반복가능객체(Iterable)로 변환한다.| -| `xs.toSeq` |컬렉션을 순서열(Seq)로 변환한다.| -| `xs.toIndexedSeq` |컬렉션을 첨자가 있는 순서열(IndexedSeq)로 변환한다.| +| `xs.toSeq` |컬렉션을 열(Seq)로 변환한다.| +| `xs.toIndexedSeq` |컬렉션을 첨자가 있는 열(IndexedSeq)로 변환한다.| | `xs.toStream` |컬렉션을 스트림(Stream)으로 변환한다.| | `xs.toSet` |컬렉션을 집합(Set)으로 변환한다.| | `xs.toMap` |컬렉션을 키/값 쌍의 맵으로 변환한다. 컬렉션의 원소가 튜플이 아니라면 이 메소드 호출은 컴파일시 타입 오류가 난다.| From 980f763a7b0a869ce9ae358ddcc6d639ff0a6859 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Wed, 26 Jun 2013 16:50:01 +1000 Subject: [PATCH 11/17] start translating sets.md --- ko/overviews/collections/sets.md | 78 ++++++++++++++++---------------- 1 file changed, 39 insertions(+), 39 deletions(-) diff --git a/ko/overviews/collections/sets.md b/ko/overviews/collections/sets.md index 35ec5faa0c..bed86159ce 100644 --- a/ko/overviews/collections/sets.md +++ b/ko/overviews/collections/sets.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: Sets +title: 집합(Set) disqus: true @@ -9,11 +9,11 @@ num: 6 language: ko --- -`Set`s are `Iterable`s that contain no duplicate elements. The operations on sets are summarized in the following table for general sets and in the table after that for mutable sets. They fall into the following categories: +`Set(집합)`은 `Iterable(반복가능)` 중에서 중복 원소가 없는 것이다. 일반적인 집합의 연산은 다음 표에 정리되어 있고, 변경 가능한 집합의 연산은 그 다음에 오는 표에 정리되어 있다. 연산들은 다음과 같은 범주에 들어간다. -* **Tests** `contains`, `apply`, `subsetOf`. The `contains` method asks whether a set contains a given element. The `apply` method for a set is the same as `contains`, so `set(elem)` is the same as `set contains elem`. That means sets can also be used as test functions that return true for the elements they contain. +* **검사** 연산으로 `contains`, `apply`, `subsetOf`가 있다. `contains` 메소드는 집합에 원소가 속해 있는지를 검사한다. 집합에 있어 `apply` 메소드는 `contains`과 동일하다. 따라서 `set(elem)`과 `set contains elem`는 같다. 따라서 집합을 원소가 포함되어있는지를 검사하는 검사 함수로 사용 가능하다. -For example +예를 들면 다음과 같다. val fruit = Set("apple", "orange", "peach", "banana") @@ -25,56 +25,56 @@ For example res1: Boolean = false -* **Additions** `+` and `++`, which add one or more elements to a set, yielding a new set. -* **Removals** `-`, `--`, which remove one or more elements from a set, yielding a new set. -* **Set operations** for union, intersection, and set difference. Each of these operations exists in two forms: alphabetic and symbolic. The alphabetic versions are `intersect`, `union`, and `diff`, whereas the symbolic versions are `&`, `|`, and `&~`. In fact, the `++` that Set inherits from `Traversable` can be seen as yet another alias of `union` or `|`, except that `++` takes a `Traversable` argument whereas `union` and `|` take sets. +* **추가** 연산에는 `+` and `++`가 있다. 이들은 집합에 하나 이상의 원소를 추가한 새 집합을 만들어 낸다. +* **제거** 연산인 `-`, `--`는 집합에서 하나 이상의 원소를 제거한 새 집합을 만들어 낸다. +* **집합 연산**으로 합집합, 교집합, 차집합이 있다. 각 연산은 두가지 버전이 존재한다. 하나는 영어문자를 사용한 것이고, 다른 하나는 기호로 된 이름을 사용한 것이다. 영문자 버전은 `intersect`, `union`, `diff`이며, 각각 순서대로 `&`, `|`, `&~`이란 기호 이름과 대응된다. 사실은 `Traversable`에서 상속받은 `++`도 `union` 또는 `|`에 대한 별칭이라 생각할수 있다. 다만 차이가 나는 것은 `++`는 `Traversable`을 매개변수로 받을 수 있지만, `union`과 `|`에는 집합만을 허용한다는 점이다. -### Operations in Class Set ### +### 집합(Set)의 연산 ### -| WHAT IT IS | WHAT IT DOES | +| 사용법 | 하는일 | | ------ | ------ | -| **Tests:** | | -| `xs contains x` |Tests whether `x` is an element of `xs`. | -| `xs(x)` |Same as `xs contains x`. | -| `xs subsetOf ys` |Tests whether `xs` is a subset of `ys`. | -| **Additions:** | | -| `xs + x` |The set containing all elements of `xs` as well as `x`.| -| `xs + (x, y, z)` |The set containing all elements of `xs` as well as the given additional elements.| -| `xs ++ ys` |The set containing all elements of `xs` as well as all elements of `ys`.| -| **Tests:** | | -| `xs - x` |The set containing all elements of `xs` except `x`.| -| `xs - (x, y, z)` |The set containing all elements of `xs` except the given elements.| -| `xs -- ys` |The set containing all elements of `xs` except the elements of `ys`.| -| `xs.empty` |An empty set of the same class as `xs`. | -| **Binary Operations:** | | -| `xs & ys` |The set intersection of `xs` and `ys`. | -| `xs intersect ys` |Same as `xs & ys`. | -| xs | ys |The set union of `xs` and `ys`. | -| `xs union ys` |Same as xs | ys. | -| `xs &~ ys` |The set difference of `xs` and `ys`. | -| `xs diff ys` |Same as `xs &~ ys`. | - -Mutable sets offer in addition methods to add, remove, or update elements, which are summarized in below. - -### Operations in Class mutable.Set ### - -| WHAT IT IS | WHAT IT DOES | +| **검사:** | | +| `xs contains x` |`x`가 `xs`의 원소인지 여부를 반환한다. | +| `xs(x)` |`xs contains x`와 같다. | +| `xs subsetOf ys` |`xs`가 `ys`의 부분집합인지 여부를 반환한다. | +| **추가:** | | +| `xs + x` |`xs`의 모든 원소와 `x`를 원소로 하는 새 집합을 반환한다.| +| `xs + (x, y, z)` |`xs`의 모든 원소와 덧붙인 모든 값들을 원소로 하는 새 집합을 반환한다.| +| `xs ++ ys` |`xs`의 모든 원소와 `ys`의 모든 원소를 원소로 하는 새 집합을 반환한다.| +| **제거:** | | +| `xs - x` |`xs`의 모든 원소 중 `x`를 제거한 나머지를 원소로 하는 새 집합을 반환한다.| +| `xs - (x, y, z)` |`xs`의 모든 원소 중 열거한 원소들을 제외한 나머지를 원소로 하는 새 집합을 반환한다.| +| `xs -- ys` |`xs`의 모든 원소 중 `ys`의 원소들을 제거한 나머지를 원소로 하는 새 집합을 반환한다.| +| `xs.empty` |`xs`와 동일한 타입의 빈 집합을 반환한다. | +| **이항 연산:** | | +| `xs & ys` |`xs`와 `ys`의 교집합 연산이다. | +| `xs intersect ys` |`xs & ys`와 같다. | +| xs | ys |`xs`와 `ys`의 합집합 연산이다. | +| `xs union ys` |xs | ys와 같다.. | +| `xs &~ ys` |`xs`와 `ys`의 차집합 연산이다. | +| `xs diff ys` |`xs &~ ys`와 같다.. | + +변경 가능한 집합은 원소를 추가, 삭제, 변경하는 연산을 추가로 제공한다. 아래 표에 정리되어 있다. + +### 변경 가능 집합(mutable.Set)의 연산 ### + +| 사용법 | 하는일 | | ------ | ------ | -| **Additions:** | | +| **추가:** | | | `xs += x` |Adds element `x` to set `xs` as a side effect and returns `xs` itself.| | `xs += (x, y, z)` |Adds the given elements to set `xs` as a side effect and returns `xs` itself.| | `xs ++= ys` |Adds all elements in `ys` to set `xs` as a side effect and returns `xs` itself.| | `xs add x` |Adds element `x` to `xs` and returns `true` if `x` was not previously contained in the set, `false` if it was.| -| **Removals:** | | +| **제거:** | | | `xs -= x` |Removes element `x` from set `xs` as a side effect and returns `xs` itself.| | `xs -= (x, y, z)` |Removes the given elements from set `xs` as a side effect and returns `xs` itself.| | `xs --= ys` |Removes all elements in `ys` from set `xs` as a side effect and returns `xs` itself.| | `xs remove x` |Removes element `x` from `xs` and returns `true` if `x` was previously contained in the set, `false` if it was not.| | `xs retain p` |Keeps only those elements in `xs` that satisfy predicate `p`.| | `xs.clear()` |Removes all elements from `xs`.| -| **Update:** | | +| **변경:** | | | `xs(x) = b` |(or, written out, `xs.update(x, b)`). If boolean argument `b` is `true`, adds `x` to `xs`, otherwise removes `x` from `xs`.| -| **Cloning:** | | +| **복제:** | | | `xs.clone` |A new mutable set with the same elements as `xs`.| Just like an immutable set, a mutable set offers the `+` and `++` operations for element additions and the `-` and `--` operations for element removals. But these are less often used for mutable sets since they involve copying the set. As a more efficient alternative, mutable sets offer the update methods `+=` and `-=`. The operation `s += elem` adds `elem` to the set `s` as a side effect, and returns the mutated set as a result. Likewise, `s -= elem` removes `elem` from the set, and returns the mutated set as a result. Besides `+=` and `-=` there are also the bulk operations `++=` and `--=` which add or remove all elements of a traversable or an iterator. From 186e6c8ba37aab4e4730056626daf9da45a74f78 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 19:41:30 +1000 Subject: [PATCH 12/17] =?UTF-8?q?sets.md=20=EC=B4=88=EB=B2=8C=EB=B2=88?= =?UTF-8?q?=EC=97=AD=EC=99=84=EB=A3=8C?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/sets.md | 62 ++++++++++++++++---------------- 1 file changed, 31 insertions(+), 31 deletions(-) diff --git a/ko/overviews/collections/sets.md b/ko/overviews/collections/sets.md index bed86159ce..eeffc1bf6f 100644 --- a/ko/overviews/collections/sets.md +++ b/ko/overviews/collections/sets.md @@ -61,25 +61,25 @@ language: ko | 사용법 | 하는일 | | ------ | ------ | | **추가:** | | -| `xs += x` |Adds element `x` to set `xs` as a side effect and returns `xs` itself.| -| `xs += (x, y, z)` |Adds the given elements to set `xs` as a side effect and returns `xs` itself.| -| `xs ++= ys` |Adds all elements in `ys` to set `xs` as a side effect and returns `xs` itself.| -| `xs add x` |Adds element `x` to `xs` and returns `true` if `x` was not previously contained in the set, `false` if it was.| +| `xs += x` |`xs`에 원소 `x`를 부작용을 사용해 추가하고, `xs` 자신을 반환한다.| +| `xs += (x, y, z)` |`xs`에 지정된 원소들을 부작용을 사용해 추가하고, `xs` 자신을 반환한다.| +| `xs ++= ys` |`xs`에 `ys`의 원소들을 부작용을 사용해 추가하고, `xs` 자신을 반환한다.| +| `xs add x` |`xs`에 원소 `x`를 부작용을 사용해 추가하되, `x`가 집합에 이미 포함되어 있었다면 거짓을, 그렇지 않았다면 참을 반환한다.| | **제거:** | | -| `xs -= x` |Removes element `x` from set `xs` as a side effect and returns `xs` itself.| -| `xs -= (x, y, z)` |Removes the given elements from set `xs` as a side effect and returns `xs` itself.| -| `xs --= ys` |Removes all elements in `ys` from set `xs` as a side effect and returns `xs` itself.| -| `xs remove x` |Removes element `x` from `xs` and returns `true` if `x` was previously contained in the set, `false` if it was not.| -| `xs retain p` |Keeps only those elements in `xs` that satisfy predicate `p`.| -| `xs.clear()` |Removes all elements from `xs`.| +| `xs -= x` |`xs`에서 원소 `x`를 부작용을 사용해 제거하고, `xs` 자신을 반환한다.| +| `xs -= (x, y, z)` |`xs`에서 지정된 원소들을 부작용을 사용해 제거하고, `xs` 자신을 반환한다.| +| `xs --= ys` |`xs`에서 `ys`의 원소들을 부작용을 사용해 제거하고, `xs` 자신을 반환한다.| +| `xs remove x` |`xs`에서 원소 `x`를 부작용을 사용해 제거하되, `x`가 집합에 이미 포함되어 있었다면 참을, 그렇지 않았다면 거짓을 반환한다.| +| `xs retain p` |`xs`에서 술어 `p`를 만족하는 원소를 남기고 나머지를 제거한다.| +| `xs.clear()` |`xs`의 모든 원소를 제거한다.| | **변경:** | | -| `xs(x) = b` |(or, written out, `xs.update(x, b)`). If boolean argument `b` is `true`, adds `x` to `xs`, otherwise removes `x` from `xs`.| +| `xs(x) = b` |(명시적으로 `xs.update(x, b)`라고 쓸 수 있음) `b`가 `true`면 `x`를 `xs`에 추가하고, 그렇지 않으면 `x`를 `xs`에서 제거한다.| | **복제:** | | -| `xs.clone` |A new mutable set with the same elements as `xs`.| +| `xs.clone` |`xs`와 같은 원소를 포함하는 새 변경 가능한 집합을 만든다.| -Just like an immutable set, a mutable set offers the `+` and `++` operations for element additions and the `-` and `--` operations for element removals. But these are less often used for mutable sets since they involve copying the set. As a more efficient alternative, mutable sets offer the update methods `+=` and `-=`. The operation `s += elem` adds `elem` to the set `s` as a side effect, and returns the mutated set as a result. Likewise, `s -= elem` removes `elem` from the set, and returns the mutated set as a result. Besides `+=` and `-=` there are also the bulk operations `++=` and `--=` which add or remove all elements of a traversable or an iterator. +변경 불가능한 집합과 마찬가지로 변경가능한 집합도 원소 추가를 위한 `+`, `++`와 원소 제거를 위한 `-`, `--` 연산을 제공한다. 하지만 이 연산들은 집합을 복사하기 때문에 변경 가능한 집합에서는 잘 사용되지 않는다. 더 효율적인 방식으로 `+=`, `-=`가 있다. `s += elem`는 `elem`을 집합 `s`에 부작용을 통해 추가하며, 결과로 집합 자신을 반환한다. 마찬가지로, `s -= elem`은 원소 `elem`을 집합에서 제거하고, 집합 자신을 결과로 반환한다. `+=`와 `-=`와 별개로 반복자나 순회가능 클래스의 원소를 한꺼번에 추가, 삭제하는 `++=`와 `--=` 연산도 있다. -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`: +메소드 이름 `+=`와 `-=`는 변경 가능하거나 불가능한 집합 모두에 아주 비슷한 코드를 사용할 수 있음을 의미한다. 먼저 변경 불가능한 집합 `s`를 사용하는 REPL 실행예를 보자. scala> var s = Set(1, 2, 3) s: scala.collection.immutable.Set[Int] = Set(1, 2, 3) @@ -88,7 +88,7 @@ The choice of the method names `+=` and `-=` means that very similar code can wo scala> s res2: scala.collection.immutable.Set[Int] = Set(1, 3, 4) -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. +여기서 타입이 `immutable.Set`인 `var`에 `+=`와 `-=` 연산을 적용했다. `s += 4` 식은 `s = s + 4`을 줄인 것이다. 따라서 집합 `s`에 대해 추가 메소드 `+`가 호출 된 다음 이 결과가 다시 변수 `s`에 대입된다. 이제 이와 비슷한 변경 가능한 집합의 동작을 살펴보자. scala> val s = collection.mutable.Set(1, 2, 3) @@ -98,43 +98,43 @@ We used `+=` and `-=` on a `var` of type `immutable.Set`. A statement such as `s scala> s -= 2 res4: s.type = Set(1, 4, 3) -The end effect is very similar to the previous interaction; we start with a `Set(1, 2, 3)` end 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. +최종 결과는 앞의 예와 아주 비슷하다. `Set(1, 2, 3)`에서 시작해서 `Set(1, 3, 4)`으로 끝난다. 비록 사용된 명령은 앞에서와 같지만 실제 하는 일은 많이 다른 것이다. `s += 4`는 이제 변경 가능한 집합 `s`의 `+=` 메소드를 호출해 집합의 내부 상태를 변경한다. 마찬가지로 `s -= 2` 또한 같은 집합의 `-=` 메소드를 호출한다. -Comparing the two interactions shows an important principle. You often can replace a mutable collection stored in a `val` by an immutable collection stored in a `var`, and _vice versa_. This works at least as long as there are no alias references to the collection through which one can observe whether it was updated in place or whether a new collection was created. +이 둘 간의 차이는 중요한 원칙을 보여준다. 바로 때로 `val`에 저장된 변경 가능한 컬렉션을 `var`에 저장된 변경 불가능한 것으로 바꾸거나, 그 _역으로_ 바꾸는 것이 가능하다는 사실이다. 외부에서 새 컬렉션이 만들어졌거나 내용이 부작용을 통해 변경되었는지를 관찰할 수 있는 동일 객체에 대한 다른 이름의 참조(alias)가 존재하지 않는 한 이 방식은 잘 동작한다. -Mutable sets also provide add and remove as variants of `+=` and `-=`. The difference is that `add` and `remove` return a Boolean result indicating whether the operation had an effect on the set. +변경 가능한 집합은 또한 `+=`와 `-=`의 변형으로 `add`와 `remove`도 제공한다. 차이는 `add`와 `remove`는 연산에 집합에 작용했는지 여부를 알려주는 불린 값을 돌려준다는 점에 있다. -The current default implementation of a mutable set uses a hashtable to store the set's elements. The default implementation of an immutable set uses a representation that adapts to the number of elements of the set. An empty set is represented by just a singleton object. Sets of sizes up to four are represented by a single object that stores all elements as fields. Beyond that size, immutable sets are implemented as [hash tries](#hash-tries). +현재 변경 가능 집합의 기본 구현은 해시 테이블을 사용해 원소를 저장한다. 변경 불가능한 집합의 기본 구현은 원소의 갯수에 따라 다른 표현방식을 사용한다. 빈 집합은 싱글턴 객체로 표현된다. 원소가 4개 이하인 집합은 모든 원소 객체를 필드로 저장하는 객체로 표현한다. 그보다 큰 변경 불가능 집합은 [해시 트라이(hash trie)](#hash-tries)로 구현되어 있다. -A consequence of these representation choices is that, for sets of small sizes (say up to 4), immutable sets are usually more compact and also more efficient than mutable sets. So, if you expect the size of a set to be small, try making it immutable. +이런 구현의 차이로 인해 더 작은 크기(4 이하)인 경우 변경 불가능한 집합이 변경 가능한 집합보다 더 작고 효율적이다. 따라서 크기가 작은 집합을 예상한다면 변경 불가능한 집합을 사용하도록 하라. -Two subtraits of sets are `SortedSet` and `BitSet`. +집합에는 `SortedSet(정렬된 집합)`과 `BitSet(비트집합)`이 있다. -### Sorted Sets ### +### 정렬된 집합 ### -A [SortedSet](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html) is a set that produces its elements (using `iterator` or `foreach`) in a given ordering (which can be freely chosen at the time the set is created). The default representation of a [SortedSet](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html) is an ordered binary tree which maintains the invariant that all elements in the left subtree of a node are smaller than all elements in the right subtree. That way, a simple in order traversal can return all tree elements in increasing order. Scala's class [immutable.TreeSet](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html) uses a _red-black_ tree implementation to maintain this ordering invariant and at the same time keep the tree _balanced_-- meaning that all paths from the root of the tree to a leaf have lengths that differ only by at most one element. +[SortedSet(정렬된 집합)](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html)은 주어진 순서에 따라 원소를 내어놓는(`iterator`나 `foreach` 사용) 집합이다(순서는 집합을 만들 때 자유롭게 결정할 수 있다). [SortedSet](http://www.scala-lang.org/api/current/scala/collection/SortedSet.html)의 기본 구현은 어떤 노드의 왼쪽 하위 트리에 속한 모든 원소가 오른쪽 하위 트리에 속한 모든 원소보다 작다는 불변조건(invariant)을 만족시키는 순서가 있는 이진 트리이다. 따라서 간단한 중위순회(in order traversal)를 통해 트리의 모든 원소를 증가하는 순서로 반환할 수 있다. 스칼라의 클래스 [immutable.TreeSet(트리집합)](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html)은 이 불변조건을 유지하면서 동시에 _균형잡힌(balanced)_ 특성을 유지하기 위해 _적-흑(red-black)_ 트리를 구현한다. 균형이 잡힌 트리는 루트(root) 노드로부터 리프(leaf) 노드에 이르는 길이가 1 이하로 차이가 나는 경우를 말한다. -To create an empty [TreeSet](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html), you could first specify the desired ordering: +빈 [TreeSet(트리집합)](http://www.scala-lang.org/api/current/scala/collection/immutable/TreeSet.html)을 만들려면 우선 원하는 순서를 지정해야 한다. scala> val myOrdering = Ordering.fromLessThan[String](_ > _) myOrdering: scala.math.Ordering[String] = ... -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() -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) -Sorted sets also support ranges of elements. For instance, the `range` method returns all elements from a starting element up to, but excluding, and 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: +정렬된 집합은 원소의 범위도 지원한다. 예를 들어 `range` 메소드는 지정된 시작 원소로부터 시작해서 지정된 끝 엘리먼트 직전까지의 모든 원소를 반환한다. `from` 메소드는 집합에서의 순서상 지정된 원소와 같거나 큰 모든 원소를 반환한다. 다음은 그 예이다. scala> res3 range ("one", "two") res4: scala.collection.immutable.TreeSet[String] = TreeSet(one, three) @@ -142,9 +142,9 @@ Sorted sets also support ranges of elements. For instance, the `range` method re res5: scala.collection.immutable.TreeSet[String] = TreeSet(three, two) -### Bitsets ### +### 비트집합(Bitset) ### -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](http://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. +[BitSet(비트집합)](http://www.scala-lang.org/api/current/scala/collection/BitSet.html)은 음이 아닌 정수 원소들로 이루어진 집합으로, 비트를 한데 묶은(packed) 하나 또는 그 이상의 워드로 되어 있다. [BitSet(비트집합)](http://www.scala-lang.org/api/current/scala/collection/BitSet.html)의 내부 표현은 `Long`의 배열을 사용한다. 첫 `Long`은 0부터 63을 나타내고, 두번째 것은 64부터 127을 나타내는 방식을 사용한다(0부터 127 사이의 수만 표현하는 변경 불가능한 비트셋은 배열을 최적화해서 한두개의 `Long` 필드만을 사용한다). 어떤 원소가 속해 있다면 해당 원소에 대응하는 `Long` 필드내의 비트가 1로 설정되고, 그렇지 않으면 0으로 설정된다. 따라서 비트집합의 크기는 내부에 저장되는 가장 큰 정수의 값에 따라 결정된다. 만약 가장 큰 정수가 `N`이라면 집합의 크기는 `N/64`개의 `Long`워드 또는 `N/8` 바이트이며, 상태정보 저장을 위해 몇 바이트가 추가된다. -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. +따라서 크기가 작은 정수 원소를 여러개 포함하는 경우 비트집합을 사용하면 다른 집합에 비해 작은 크기로 가능하다. 비트 집합의 또 다른 잇점은 `contains`를 사용한 포함관계 검사나 `+=`, `-=` 등을 사용한 원소 추가/제거가 모두 아주 효율적이라는 점이다. From 9d5ae457f53ded89fdf5dffaa2f9f087912f680e Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 25 Jun 2013 21:41:20 +1000 Subject: [PATCH 13/17] =?UTF-8?q?maps.md=20=EB=B2=88=EC=97=AD=EC=A4=91.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- ko/overviews/collections/maps.md | 66 ++++++++++++++++---------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/ko/overviews/collections/maps.md b/ko/overviews/collections/maps.md index 9030033abb..016fc90e20 100644 --- a/ko/overviews/collections/maps.md +++ b/ko/overviews/collections/maps.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: Maps +title: 맵(Map) disqus: true @@ -9,42 +9,42 @@ num: 7 language: ko --- -A [Map](http://www.scala-lang.org/api/current/scala/collection/Map.html) is an [Iterable](http://www.scala-lang.org/api/current/scala/collection/Iterable.html) consisting of pairs of keys and values (also named _mappings_ or _associations_). Scala's [Predef](http://www.scala-lang.org/api/current/scala/Predef$.html) class offers an implicit conversion that lets you write `key -> value` as an alternate syntax for the pair `(key, value)`. For instance `Map("x" -> 24, "y" -> 25, "z" -> 26)` means exactly the same as `Map(("x", 24), ("y", 25), ("z", 26))`, but reads better. +[Map(맵)](http://www.scala-lang.org/api/current/scala/collection/Map.html)은 키와 값의 쌍으로 구성된 [Iterable(반복가능)](http://www.scala-lang.org/api/current/scala/collection/Iterable.html)한 컬렉션이다(_맵핑_ 또는 _연관_ 이라고도 한다). 스칼라의 [Predef](http://www.scala-lang.org/api/current/scala/Predef$.html) 클래스에는 `key -> value`를 `(key, value)` 대신 쓸수 있도록 하는 묵시적 변환이 정의되어 있다. 예를 들어 `Map("x" -> 24, "y" -> 25, "z" -> 26)`와 `Map(("x", 24), ("y", 25), ("z", 26))`는 의미가 완전히 동일하다. 다만 전자가 더 보기 좋을 뿐이다. -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. -* **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. -* **Transformations** `filterKeys` and `mapValues`, which produce a new map by filtering and transforming bindings of an existing map. +* **찾기** 연산 `apply`, `get`, `getOrElse`, `contains`, `isDefinedAt` 들은 맵을 키를 받아 값을 반환하는 부분함수로 바꾼다. 맵에서 바탕이 되는 찾기 메소드는 `def get(key): Option[Value]`이다. 연산 "`m get key`"는 맵에 주어진 `key`와 대응하는 연관관계쌍이 들어 있는지를 본다. 만약 그런 쌍이 있다면 그 연관쌍을 `Some`으로 포장해서 내어 놓는다. 맵에 키가 정의되어 있지 않다면 `get`은 `None`을 반환한다. 맵에는 또한 키에 대해 값을 `Option`으로 감싸지 않고 바로 반환하는 `apply` 메소드도 정의되어 있다. 만약 키가 없다면 예외가 발생한다. +* **추가와 변경** 연산 `+`, `++`, `updated`를 사용하면 새로운 연관관계를 맵에 추가하거나, 기존의 관계를 변경할 수 있다. +* **제거** 연산 `-`, `--`는 맵에서 연관 관계를 제거하기 위해 사용한다. +* **부분 컬렉션** 생성 메소드 `keys`, `keySet`, `keysIterator`, `values`, `valuesIterator`는 맵의 모든 키나 모든 값을 별도로 여러 형태로 반환한다. +* **변환** 연산 `filterKeys`와 `mapValues`는 맵을 필터링해 새 맵을 만들거나 기존 맵의 연관관계를 변환할 때 사용한다. -### Operations in Class Map ### +### 맵 클래스의 연산 ### -| WHAT IT IS | WHAT IT DOES | +| 사용법 | 하는일 | | ------ | ------ | -| **Lookups:** | | -| `ms get k` |The value associated with key `k` in map `ms` as an option, `None` if not found.| -| `ms(k)` |(or, written out, `ms apply k`) The value associated with key `k` in map `ms`, or exception if not found.| -| `ms getOrElse (k, d)` |The value associated with key `k` in map `ms`, or the default value `d` if not found.| -| `ms contains k` |Tests whether `ms` contains a mapping for key `k`.| -| `ms isDefinedAt k` |Same as `contains`. | -| **Additions and Updates:**| | -| `ms + (k -> v)` |The map containing all mappings of `ms` as well as the mapping `k -> v` from key `k` to value `v`.| -| `ms + (k -> v, l -> w)` |The map containing all mappings of `ms` as well as the given key/value pairs.| -| `ms ++ kvs` |The map containing all mappings of `ms` as well as all key/value pairs of `kvs`.| -| `ms updated (k, v)` |Same as `ms + (k -> v)`.| -| **Removals:** | | -| `ms - k` |The map containing all mappings of `ms` except for any mapping of key `k`.| -| `ms - (k, 1, m)` |The map containing all mappings of `ms` except for any mapping with the given keys.| -| `ms -- ks` |The map containing all mappings of `ms` except for any mapping with a key in `ks`.| -| **Subcollections:** | | +| **찾기:** | | +| `ms get k` |맵 `ms`에 있는 키 `k`에 대응하는 값을 옵션으로 반환한다. 찾을 수 없다면 `None`이 반환된다.| +| `ms(k)` |(`ms apply k`라고 명시적으로 쓸 수 있음) 맵 `ms`에서 키 `k`에 대응하는 값을 반환한다. 값이 없다면 예외를 던진다.| +| `ms getOrElse (k, d)` |맵 `ms`에서 키 `k`에 대응하는 값을 반환한다. 값이 없다면 디폴트 값으로 지정된 `d`를 반환한다.| +| `ms contains k` |맴 `ms`에 키 `k`에 대한 맵핑이 정의되어 있는지 여부를 반환한다.| +| `ms isDefinedAt k` |`contains`와 같다. | +| **추가와 변경:**| | +| `ms + (k -> v)` |`ms`의 모든 연관관계와 더불어 맵핑 `k -> v`, 즉 키 `k`에서 `v`로 가는 연관관계가 추가된 맵을 반환한다.| +| `ms + (k -> v, l -> w)` |`ms`의 모든 연관관계와 더불어 주어진 모든 키-값 연관관계가 추가된 맵을 반환한다.| +| `ms ++ kvs` |`ms`의 모든 연관관계와 더불어 `kvs`에 있는 연관관계가 추가된 맵을 반환한다. (단, `kvs`는 튜플이 원소이거나 맵 타입이어야 정상적으로 동작한다.)| +| `ms updated (k, v)` |`ms + (k -> v)`과 같다.| +| **제거:** | | +| `ms - k` |`ms`의 모든 연관관계 중에서 키 `k`에 대한 연관관계만이 포함되지 않은 맵을 반환한다.| +| `ms - (k, 1, m)` |`ms`의 모든 연관관계 중에서 주어진 여러 키들에 대한 연관관계들이 포함되지 않은 맵을 반환한다.| +| `ms -- ks` |`ms`의 모든 연관관계 중에서 `ks`에 있는 키들에 대한 연관관계들이 포함되지 않은 맵을 반환한다.| +| **부분 컬렉션 :** | | | `ms.keys` |An iterable containing each key in `ms`. | | `ms.keySet` |A set containing each key in `ms`. | | `ms.keyIterator` |An iterator yielding each key in `ms`. | | `ms.values` |An iterable containing each value associated with a key in `ms`.| | `ms.valuesIterator` |An iterator yielding each value associated with a key in `ms`.| -| **Transformation:** | | +| **변환:** | | | `ms filterKeys p` |A map view containing only those mappings in `ms` where the key satisfies predicate `p`.| | `ms mapValues f` |A map view resulting from applying function `f` to each value associated with a key in `ms`.| @@ -53,25 +53,25 @@ Mutable maps support in addition the operations summarized in the following tabl ### Operations in Class mutable.Map ### -| WHAT IT IS | WHAT IT DOES | +| 사용법 | 하는일 | | ------ | ------ | -| **Additions and Updates:**| | -| `ms(k) = v` |(Or, written out, `ms.update(x, v)`). Adds mapping from key `k` to value `v` to map ms as a side effect, overwriting any previous mapping of `k`.| +| **추가와 변경:**| | +| `ms(k) = v` |(`ms.update(x, v)`라고 명시적으로 쓸 수도 있음). 키 `k`에서 값 `v`로 가는 맵핑을 맵 `ms`에 부작용을 사용해 추가한다. 이미 키 `k`에 대한 값이 정의되어 있었다면 이를 덮어쓴다.| | `ms += (k -> v)` |Adds mapping from key `k` to value `v` to map `ms` as a side effect and returns `ms` itself.| | `ms += (k -> v, l -> w)` |Adds the given mappings to `ms` as a side effect and returns `ms` itself.| | `ms ++= kvs` |Adds all mappings in `kvs` to `ms` as a side effect and returns `ms` itself.| | `ms put (k, v)` |Adds mapping from key `k` to value `v` to `ms` and returns any value previously associated with `k` as an option.| | `ms getOrElseUpdate (k, d)`|If key `k` is defined in map `ms`, return its associated value. Otherwise, update `ms` with the mapping `k -> d` and return `d`.| -| **Additions and Updates:**| | +| **제거:**| | | `ms -= k` |Removes mapping with key `k` from ms as a side effect and returns `ms` itself.| | `ms -= (k, l, m)` |Removes mappings with the given keys from `ms` as a side effect and returns `ms` itself.| | `ms --= ks` |Removes all keys in `ks` from `ms` as a side effect and returns `ms` itself.| | `ms remove k` |Removes any mapping with key `k` from `ms` and returns any value previously associated with `k` as an option.| | `ms retain p` |Keeps only those mappings in `ms` that have a key satisfying predicate `p`.| | `ms.clear()` |Removes all mappings from `ms`. | -| **Transformation:** | | +| **변환:** | | | `ms transform f` |Transforms all associated values in map `ms` with function `f`.| -| **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. As is the for sets, mutable maps also support the non-destructive addition operations `+`, `-`, and `updated`, but they are used less frequently because they involve a copying of the mutable map. Instead, a mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There are 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. From 9708474e3b1217d8dddf1aa5cab2ce3b91147fa3 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Fri, 28 Jun 2013 00:29:48 +1000 Subject: [PATCH 14/17] maps.md more --- ko/overviews/collections/maps.md | 44 ++++++++++++++++---------------- 1 file changed, 22 insertions(+), 22 deletions(-) diff --git a/ko/overviews/collections/maps.md b/ko/overviews/collections/maps.md index 016fc90e20..a4b02ae945 100644 --- a/ko/overviews/collections/maps.md +++ b/ko/overviews/collections/maps.md @@ -39,40 +39,40 @@ language: ko | `ms - (k, 1, m)` |`ms`의 모든 연관관계 중에서 주어진 여러 키들에 대한 연관관계들이 포함되지 않은 맵을 반환한다.| | `ms -- ks` |`ms`의 모든 연관관계 중에서 `ks`에 있는 키들에 대한 연관관계들이 포함되지 않은 맵을 반환한다.| | **부분 컬렉션 :** | | -| `ms.keys` |An iterable containing each key in `ms`. | -| `ms.keySet` |A set containing each key in `ms`. | -| `ms.keyIterator` |An iterator yielding each key in `ms`. | -| `ms.values` |An iterable containing each value associated with a key in `ms`.| -| `ms.valuesIterator` |An iterator yielding each value associated with a key in `ms`.| +| `ms.keys` |`ms`의 모든 키를 포함하는 반복가능 객체를 반환한다. | +| `ms.keySet` |`ms`의 모든 키를 포함하는 집합 객체를 반환한다. | +| `ms.keyIterator` |`ms`의 키를 내어놓는 반복자를 반환한다. | +| `ms.values` |`ms`에서 키에 연관된 모든 값을 포함하는 반복가능 객체를 반환한다. | +| `ms.valuesIterator` |`ms`에서 키에 연관된 모든 값을 포함하는 반복자를 반환한다. | | **변환:** | | -| `ms filterKeys p` |A map view containing only those mappings in `ms` where the key satisfies predicate `p`.| -| `ms mapValues f` |A map view resulting from applying function `f` to each value associated with a key in `ms`.| +| `ms filterKeys p` |`ms`에서 키가 술어 `p`를 만족하는 연관관계만을 포함하는 새 맵 뷰를 반환한다.| +| `ms mapValues f` |`ms`에서 키에 연관된 모든 값에 대해 함수 `f`를 적용해 얻을 수 있는 새 맵 뷰를 반환한다.| -Mutable maps support in addition the operations summarized in the following table. +변경 가능 맵은 아래 표에 정리된 연산을 추가로 지원한다. -### Operations in Class mutable.Map ### +### mutable.Map 클래스에 정의된 연산 ### | 사용법 | 하는일 | | ------ | ------ | | **추가와 변경:**| | | `ms(k) = v` |(`ms.update(x, v)`라고 명시적으로 쓸 수도 있음). 키 `k`에서 값 `v`로 가는 맵핑을 맵 `ms`에 부작용을 사용해 추가한다. 이미 키 `k`에 대한 값이 정의되어 있었다면 이를 덮어쓴다.| -| `ms += (k -> v)` |Adds mapping from key `k` to value `v` to map `ms` as a side effect and returns `ms` itself.| -| `ms += (k -> v, l -> w)` |Adds the given mappings to `ms` as a side effect and returns `ms` itself.| -| `ms ++= kvs` |Adds all mappings in `kvs` to `ms` as a side effect and returns `ms` itself.| -| `ms put (k, v)` |Adds mapping from key `k` to value `v` to `ms` and returns any value previously associated with `k` as an option.| -| `ms getOrElseUpdate (k, d)`|If key `k` is defined in map `ms`, return its associated value. Otherwise, update `ms` with the mapping `k -> d` and return `d`.| +| `ms += (k -> v)` |키 `k`에서 값 `v`로 가는 맵핑을 맵 `ms`에 부작용을 사용해 추가하고 `ms` 자신을 반환한다.| +| `ms += (k -> v, l -> w)` |지정된 맵핑들을 맵 `ms`에 부작용을 사용해 추가하고 `ms` 자신을 반환한다.| +| `ms ++= kvs` |`kvs`에 있는 모든 연관관계들을 맵 `ms`에 부작용을 사용해 추가하고 `ms` 자신을 반환한다.| +| `ms put (k, v)` |키 `k`에서 값 `v`로 가는 맵핑을 맵 `ms`에 부작용을 사용해 추가하고, 이전에 `k`와 연관된 값이 있었다면 이를 옵션 객체로 반환한다.| +| `ms getOrElseUpdate (k, d)`|키 `k`가 맵 `ms`에 정의되어 있다면 그 값을 반환하고, 그렇지 않다면 `ms`에 새 연관관계 `k -> d`를 추가한 다음 `d`를 반환한다.| | **제거:**| | -| `ms -= k` |Removes mapping with key `k` from ms as a side effect and returns `ms` itself.| -| `ms -= (k, l, m)` |Removes mappings with the given keys from `ms` as a side effect and returns `ms` itself.| -| `ms --= ks` |Removes all keys in `ks` from `ms` as a side effect and returns `ms` itself.| -| `ms remove k` |Removes any mapping with key `k` from `ms` and returns any value previously associated with `k` as an option.| -| `ms retain p` |Keeps only those mappings in `ms` that have a key satisfying predicate `p`.| -| `ms.clear()` |Removes all mappings from `ms`. | +| `ms -= k` |키 `k`에 해당하는 맵핑을 맵 `ms`에서 부작용을 사용해 제거한 후, `ms`자신을 반환한다.| +| `ms -= (k, l, m)` |지정된 키들에 해당하는 맵핑을 맵 `ms`에서 부작용을 사용해 제거한 후, `ms`자신을 반환한다.| +| `ms --= ks` |`ks`에 있는 키들에 해당하는 맵핑을 맵 `ms`에서 부작용을 사용해 제거한 후, `ms`자신을 반환한다.| +| `ms remove k` |키 `k`에 대한 맵핑을 맵 `ms`에서 부작용을 사용해 제거하고, 이전에 `k`와 연관된 값이 있었다면 이를 옵션 객체로 반환한다.| +| `ms retain p` |`ms`에서 (키,값) 튜플에 대한 술어 `p`를 만족하는 연관 관계들만 남기고 나머지는 다 제거한 다음, `ms` 자신을 반환한다| +| `ms.clear()` |`ms`에서 모든 매핑을 제거한 다음, | | **변환:** | | -| `ms transform f` |Transforms all associated values in map `ms` with function `f`.| +| `ms transform f` |`ms`의 모든 연관 쌍을 `f`를 사용해 변환한다. `ms`자신을 반환한다.| | **복사:** | | -| `ms.clone` |Returns a new mutable map with the same mappings as `ms`.| +| `ms.clone` |`ms`과 같은 맵핑들을 포함하는 새로운 변경가능한 맵을 반환한다.| The addition and removal operations for maps mirror those for sets. As is the for sets, mutable maps also support the non-destructive addition operations `+`, `-`, and `updated`, but they are used less frequently because they involve a copying of the mutable map. Instead, a mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There are 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. From 1eddcd7cb7cd6f5c4040d8be9d26561041a3939b Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Sun, 30 Jun 2013 16:08:54 +1000 Subject: [PATCH 15/17] maps more --- ko/overviews/collections/maps.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ko/overviews/collections/maps.md b/ko/overviews/collections/maps.md index a4b02ae945..eb8a4678dc 100644 --- a/ko/overviews/collections/maps.md +++ b/ko/overviews/collections/maps.md @@ -74,21 +74,21 @@ language: ko | **복사:** | | | `ms.clone` |`ms`과 같은 맵핑들을 포함하는 새로운 변경가능한 맵을 반환한다.| -The addition and removal operations for maps mirror those for sets. As is the for sets, mutable maps also support the non-destructive addition operations `+`, `-`, and `updated`, but they are used less frequently because they involve a copying of the mutable map. Instead, a mutable map `m` is usually updated "in place", using the two variants `m(key) = value` or `m += (key -> value)`. There are 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. +맵의 추가와 제거 연산은 집합의 그것과 비슷하다. 집합에서와 마찬가지로 변경 가능한 맵도 부작용을 사용하지 않는 추가 연산 `+`, `-`, `updated`를 지원한다. 하지만 이런 연산들은 변경 가능 맵을 복사하기 때문에 자주 사용되지는 않는다. 대신 변경 가능한 맵 `m`은 보통 "그 자리에서" `m(key) = value`이나 `m += (key -> value)` 연산을 사용해 변경된다. 업데이트 연산에는 이전에 `key`와 연관되어 있던 값을 `Option`으로 돌려주는 `m put (key, value)`도 있다. `put`은 만약 `key`가 맵에 존재하지 않았다면 `None`을 반환한다. -The `getOrElseUpdate` is useful for accessing maps that act as caches. Say you have an expensive computation triggered by invoking a function `f`: +`getOrElseUpdate`는 캐시처럼 동작하는 맵을 억세스할 때 유용하다. `f`를 호출하면 비용이 많이 드는 계산을 수행해야 하는 경우를 생각해 보자. scala> def f(x: String) = { println("taking my time."); sleep(100) x.reverse } f: (x: String)String -Assume further that `f` has no side-effects, so invoking it again with the same argument will always yield the same result. In that case you could save time by storing previously computed bindings of argument and results of `f` in a map and only computing the result of `f` if a result of an argument was not found there. One could say the map is a _cache_ for the computations of the function `f`. +더 나아가 `f`에 부작용이 없다고 한다면, 동일한 인자로 이 함수를 호출할 때마다 항상 같은 결과를 받을 것이다. 이런 경우 예전에 계산했던 값을 인자와 `f`의 결과값을 연관시켜 맴에 저장해 두고, 새로운 인자 값이 들어와 맵에서 예전에 계산해 둔 결과를 찾을 수 없는 경우에만 `f`의 결과를 계산하게 한다면 비용이 줄어든다. 이 경우 맵을 함수 `f`의 계산 결과에 대한 _캐시(cache)_ 라 부를 수도 있다. val cache = collection.mutable.Map[String, String]() cache: scala.collection.mutable.Map[String,String] = Map() -You can now create a more efficient caching version of the `f` function: +이제 더 효율이 좋은 `f` 함수의 캐시된 버전을 만들 수 있다. scala> def cachedF(s: String) = cache.getOrElseUpdate(s, f(s)) cachedF: (s: String)String @@ -98,7 +98,7 @@ You can now create a more efficient caching version of the `f` function: scala> cachedF("abc") res4: String = cba -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: +`getOrElseUpdate`의 두번째 인자는 "이름에 의한 호출(by-name)"이므로, 위의 `f("abc")` 계산은 오직 `getOrElseUpdate`가 두번째 인자 값을 필요로 하는 경우에만 수행된다. 이는 정확하게 말하자면 첫 번째 인자를 `cache` 맵에서 못 찾은 경우이다. 맵의 기본 연산을 활용해 `cachedF`를 직접 구현할 수도 있었겠지만, 그렇게 하려면 조금 길게 코드를 작성해야 한다. def cachedF(arg: String) = cache get arg match { case Some(result) => result From ce3ac4e7ee7e4e87ba5036dd10a400b3e9122664 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Mon, 1 Jul 2013 15:23:17 +1000 Subject: [PATCH 16/17] maps translation finished --- ko/overviews/collections/maps.md | 20 +++++++++++--------- ko/overviews/collections/sets.md | 1 + ko/overviews/collections/trait-iterable.md | 2 +- 3 files changed, 13 insertions(+), 10 deletions(-) diff --git a/ko/overviews/collections/maps.md b/ko/overviews/collections/maps.md index eb8a4678dc..e447e5aea2 100644 --- a/ko/overviews/collections/maps.md +++ b/ko/overviews/collections/maps.md @@ -108,9 +108,9 @@ language: ko result } -### Synchronized Sets and Maps ### +### 동기화된 집합과 맵 ### -To get a thread-safe mutable map, you can mix the `SynchronizedMap` trait trait into whatever particular map implementation you desire. For example, you can mix `SynchronizedMap` into `HashMap`, as shown in the code below. This example begins with an import of two traits, `Map` and `SynchronizedMap`, and one class, `HashMap`, from package `scala.collection.mutable`. The rest of the example is the definition of singleton object `MapMaker`, which declares one method, `makeMap`. The `makeMap` method declares its result type to be a mutable map of string keys to string values. +쓰레드 안전한 변경 가능한 맵을 만들고 싶다면 `SynchronizedMap` 트레잇을 원하는 맵 구현에 끼워 넣으면 된다. 예를 들어 아래 코드처럼 `SynchronizedMap`을 `HashMap`에 끼워 넣을 수 있다. 아래 예제는 두 트레잇 `Map`과 `SynchronizedMap`, 그리고 클래스 `HashMap`을 패키지 `scala.collection.mutable`에서 임포트한다. 나머지 부분은 싱글턴 `MapMaker`를 만드는 것이다. 이 객체는 메소드 `makeMap`를 구현한다. `makeMap` 메소드는 문자열에서 문자열로 맵핑하는 동기화된 해시맵을 반환한다. import scala.collection.mutable.{Map, SynchronizedMap, HashMap} @@ -124,21 +124,21 @@ To get a thread-safe mutable map, you can mix the `SynchronizedMap` trait trait } } -
Mixing in the `SynchronizedMap` trait.
+
`SynchronizedMap`트레잇 끼워 넣기
-The first statement inside the body of `makeMap` constructs a new mutable `HashMap` that mixes in the `SynchronizedMap` trait: +`makeMap`의 첫 문장은 새로운 변경 가능한 `HashMap`을 만들고 `SynchronizedMap` 트레잇을 끼워 넣는다. new HashMap[String, String] with SynchronizedMap[String, String] -Given this code, the Scala compiler will generate a synthetic subclass of `HashMap` that mixes in `SynchronizedMap`, and create (and return) an instance of it. This synthetic class will also override a method named `default`, because of this code: +스칼라 컴파일러는 이 코드를 보고 `SynchronizedMap`을 끼워 넣은 `HashMap`의 하위 클래스를 만들고, 그 클래스의 인스턴스를 만든다(그리고 반환한다). 이 합성 클래스는 아래와 같이 `default`라는 메소드를 재정의한다. override def default(key: String) = "Why do you want to know?" -If you ask a map to give you the value for a particular key, but it doesn't have a mapping for that key, you'll by default get a `NoSuchElementException`. If you define a new map class and override the `default` method, however, your new map will return the value returned by `default` when queried with a non-existent key. Thus, the synthetic `HashMap` subclass generated by the compiler from the code in the synchronized map code will return the somewhat curt response string, `"Why do you want to know?"`, when queried with a non-existent key. +사용자가 맵에게 어떤 키와 연관된 값을 물어봤는데 그런 연관이 맵에 존재하지 않는다면 기본 동작은 `NoSuchElementException` 예외를 발생시키는 것이다. 하지만 새 맵 클래스를 만들면서 `default` 메소드를 재정의하면 존재하지 않는 키에 대한 질의가 들어올 때 `default` 메소드가 정의하는 값을 반환하게 된다. 따라서 컴파일러가 만든 동기화된 합성 `HashMap` 하위 클래스는 존재하지 않는 키에 대한 질의를 받으면 `"Why do you want to know?"`라는 문자열을 반환한다. -Because the mutable map returned by the `makeMap` method mixes in the `SynchronizedMap` trait, it can be used by multiple threads at once. Each access to the map will be synchronized. Here's an example of the map being used, by one thread, in the interpreter: +`makeMap` 메소드가 반환하는 변경 가능한 맵에 `SynchronizedMap` 트레잇을 끼워 넣었기 때문에, 동시에 여러 쓰레드에서 이를 사용할 수 있다. 맵에 대한 억세스는 동기화될 것이다. 다음은 인터프리터상에서 한 쓰레드를 사용해 이 맵을 사용하는 예를 보여준다. scala> val capital = MapMaker.makeMap capital: scala.collection.mutable.Map[String,String] = Map() @@ -154,11 +154,13 @@ Because the mutable map returned by the `makeMap` method mixes in the `Synchroni scala> capital("New Zealand") res3: String = Wellington -You can create synchronized sets similarly to the way you create synchronized maps. For example, you could create a synchronized `HashSet` by mixing in the `SynchronizedSet` trait, like this: +동기화된 맵을 만드는 것과 비슷한 방식으로 동기화된 집합도 만들 수 있다. 예를 들어 `SynchronizedSet` 트레잇을 끼워 넣으면 동기화된 `HashSet`을 만들 수 있다. 다음과 같다. import scala.collection.mutable val synchroSet = new mutable.HashSet[Int] with mutable.SynchronizedSet[Int] -Finally, if you are thinking of using synchronized collections, you may also wish to consider the concurrent collections of `java.util.concurrent` instead. +마지막으로, 어떤 상황에서 동기화된 컬렉션을 사용하는 것을 고려하게 된다면, 그 상황이 `java.util.concurrent` 컬렉션을 필요로 하는 경우는 아닌지 한번 더 생각해 보도록 하라. + +번역: 오현석(enshahar@gmail.com) diff --git a/ko/overviews/collections/sets.md b/ko/overviews/collections/sets.md index eeffc1bf6f..aee1bf3267 100644 --- a/ko/overviews/collections/sets.md +++ b/ko/overviews/collections/sets.md @@ -148,3 +148,4 @@ res3: scala.collection.immutable.TreeSet[String] = TreeSet(four, one, three, two 따라서 크기가 작은 정수 원소를 여러개 포함하는 경우 비트집합을 사용하면 다른 집합에 비해 작은 크기로 가능하다. 비트 집합의 또 다른 잇점은 `contains`를 사용한 포함관계 검사나 `+=`, `-=` 등을 사용한 원소 추가/제거가 모두 아주 효율적이라는 점이다. +번역: 오현석(enshahar@gmail.com) \ No newline at end of file diff --git a/ko/overviews/collections/trait-iterable.md b/ko/overviews/collections/trait-iterable.md index 77e949c15e..3b89b814de 100644 --- a/ko/overviews/collections/trait-iterable.md +++ b/ko/overviews/collections/trait-iterable.md @@ -39,7 +39,7 @@ language: ko `Traversable` 트레잇의 메소드 중 이터레이터가 있는 경우에만 효율적으로 구현할 수 있는 메소드 몇 가지를 `Iterable` 트레잇에서 재정의하고 있다. 다음 표에서 이를 요약하였다. -### Iterable 트레잇의 연산들 ### +### Iterable 트레잇의 연산 ### | 사용법 | 하는일 | | ------ | ------ | From eedccfc3ddf98d8103b7e7b6baefe7ec9ba53579 Mon Sep 17 00:00:00 2001 From: Hyunsok Oh Date: Tue, 2 Jul 2013 16:28:44 +1000 Subject: [PATCH 17/17] translation of concrete immutable collection.md start --- .../concrete-immutable-collection-classes.md | 31 +++++++++---------- 1 file changed, 15 insertions(+), 16 deletions(-) diff --git a/ko/overviews/collections/concrete-immutable-collection-classes.md b/ko/overviews/collections/concrete-immutable-collection-classes.md index 5d06c842b1..ba9de1ec8c 100644 --- a/ko/overviews/collections/concrete-immutable-collection-classes.md +++ b/ko/overviews/collections/concrete-immutable-collection-classes.md @@ -1,6 +1,6 @@ --- layout: overview-large -title: Concrete Immutable Collection Classes +title: 변경 불가능한 컬렉션에 속하는 구체적인 클래스들 disqus: true @@ -9,42 +9,41 @@ num: 8 language: ko --- -Scala provides many concrete immutable collection classes for you to choose from. They differ in the traits they implement (maps, sets, sequences), whether they can be infinite, and the speed of various operations. Here are some of the most common immutable collection types used in Scala. +스칼라에는 필요에 따라 선택 가능한 구체적인 선택 불가능 컬렉션 클래스가 많이 있다. 각각의 차이는 어떤 트레잇을 구현하고 있는가(맵, 집합, 열), 무한한가 유한한가, 각각의 연산의 수행 시간(복잡도) 등에 있다. 여기서는 스칼라에서 가장 많이 사용되는 변경 불가능한 컬렉션 타입들을 설명할 것이다. -## Lists +## 리스트(List) -A [List](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/List.html) is a finite immutable sequence. They provide constant-time access to their first element as well as the rest of the list, and they have a constant-time cons operation for adding a new element to the front of the list. Many other operations take linear time. +[List(리스트)](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/List.html)는 유한한 변경 불가능한 열이다. 리스트의 첫 원소를 가져오거나, 첫 원소를 제외한 나머지를 가져오는 연산에는 상수 시간이 걸린다. 또한 새 원소를 리스트 맨 앞에 붙이는(보통 콘스cons라 부름) 연산도 상수시간이 소요된다. 다른 연산들은 보통 선형 시간(즉, 리스트의 길이 N에 비례)이 걸린다. -Lists have always been the workhorse for Scala programming, so not much needs to be said about them here. The major change in 2.8 is that the `List` class together with its subclass `::` and its subobject `Nil` is now defined in package `scala.collection.immutable`, where it logically belongs. There are still aliases for `List`, `Nil`, and `::` in the `scala` package, so from a user perspective, lists can be accessed as before. +리스트는 계속해서 스칼라 프로그래밍시 사용하는 주요 데이터 구조였다. 따라서 여기서 다시 자세히 설명할 필요는 없을 것이다. 2.8에서 가장 큰 변화는 `List` 클래스, 그리고 그 하위 클래스인 `::`와 하위 객체 `Nil`이 이제는 논리적인 위치에 맞게 `scala.collection.immutable` 패키지에 들어가 있다는 점이다. 여전히 `scala` 패키지에도 타입 별칭 `List`, `Nil`, `::`가 존재한다. 따라서 사용자 관점에서 볼때는 예전에 사용하던 방식대로 계속 사용 가능하다. -Another change is that lists now integrate more closely into the collections framework, and are less of a special case than before. For instance all of the numerous methods that originally lived in the `List` companion object have been deprecated. They are replaced by the [uniform creation methods]({{ site.baseurl }}/overviews/collections/creating-collections-from-scratch.html) inherited by every collection. +또 다른 변화는 이제 리스트도 컬렉션 프레임워크에 더 밀접하게 통합되어 있따는 점이다. 따라서 이전보다 덜 특별하게 취급된다. 예를 들어 원래는 `List` 짝 객체에 존재하던 여러 연산이 이제는 사용하지 않도록 표시되었다. 이러한 연산들은 모든 컬렉션이 상속하는 [일정한 생성 메소드들]({{ site.baseurl }}/overviews/collections/creating-collections-from-scratch.html)로 대치되었다. -## Streams +## 스트림 -A [Stream](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Stream.html) is like a list except that its elements are computed lazily. Because of this, a stream can be infinitely long. Only those elements requested are computed. Otherwise, streams have the same performance characteristics as lists. - -Whereas lists are constructed with the `::` operator, streams are constructed with the similar-looking `#::`. Here is a simple example of a stream containing the integers 1, 2, and 3: +[Stream(스트림)](http://www.scala-lang.org/api/{{ site.scala-version }}/scala/collection/immutable/Stream.html)은 리스트와 같지만 각 원소가 지연계산된다는 점에서 차이가 있다. 따라서 무한한 스트림도 가능하다. 요청을 받을 때만 원소를 계산한다. 그 점을 제외하면 나머지 동작 특성은 리스트와 같다. +리스트가 `::` 연산으로 구성되는 반면, 스트림은 비슷한 `#::`로 구성된다. 다음은 정수 1, 2, 3을 포함하는 스트림을 만드는 과정을 보여준다. scala> val str = 1 #:: 2 #:: 3 #:: Stream.empty str: scala.collection.immutable.Stream[Int] = Stream(1, ?) -The head of this stream is 1, and the tail of it has 2 and 3. The tail is not printed here, though, because it hasn't been computed yet! Streams are specified to compute lazily, and the `toString` method of a stream is careful not to force any extra evaluation. - -Below is a more complex example. It computes a stream 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. +이 스트림의 머리는 1이고, 꼬리는 2와 3이다. 꼬리는 출력이 되지 않는다. 왜냐하면 아직 그 값을 계산하지 않았기 때문이다! 스트림은 지연계산을 위한 것이기 때문에, 스트림의 `toString` 메소드는 추가 계산을 수행하지 않게 조심하도록 구현되어 있다. +다음은 좀 더 복잡한 예제이다. 이 예에서는 주어진 두 정수로 시작하는 피보나치 수열의 스트림을 계산한다. 피보나치 수열은 각 원소가 바로 이전 두 원소의 합인 수열이다. scala> def fibFrom(a: Int, b: Int): Stream[Int] = a #:: fibFrom(b, a + b) fibFrom: (a: Int,b: Int)Stream[Int] -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: +이 함수는 믿을 수 없이 간단하다. 열의 첫번째 원소는 분명 `a`이고, 나머지 열은 `b` 다음에 `a + b`가 오는 피보나치 수열이다. 교묘한 부분은 이 열을 계산할 때 무한한 재귀호출을 하지 않는다는 점이다. `::`를 `#::` 대신 사용했다면 함수 호출이 자기 자신을 호출하게 되어서 무한 재귀 호출이 발생했을 것이다. 하지만 `#::`를 사용하기 때문에 우항은 요청되기 전까지 계산되지 않는다. + +다음은 1을 두개 사용해 생성되는 피보나치 수열의 앞 부분 항을 몇 개 보여준다. scala> val fibs = fibFrom(1, 1).take(7) fibs: scala.collection.immutable.Stream[Int] = Stream(1, ?) scala> fibs.toList res9: List[Int] = List(1, 1, 2, 3, 5, 8, 13) -## Vectors +## 벡터 Lists are very efficient when the algorithm processing them is careful to only process their heads. Accessing, adding, and removing the head of a list takes only constant time, whereas accessing or modifying elements later in the list takes time linear in the depth into the list.