{"id":644,"date":"2011-10-06T17:06:00","date_gmt":"2011-10-06T17:06:00","guid":{"rendered":"http:\/\/www.javacodegeeks.com\/2012\/10\/scala-tutorial-maps-sets-groupby-options-flatten-flatmap.html"},"modified":"2012-10-21T20:31:48","modified_gmt":"2012-10-21T20:31:48","slug":"scala-tutorial-maps-sets-groupby","status":"publish","type":"post","link":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html","title":{"rendered":"Scala Tutorial &#8211; Maps, Sets, groupBy, Options, flatten, flatMap"},"content":{"rendered":"<div dir=\"ltr\" style=\"text-align: left\">\n<h2>    Preface<\/h2>\n<p>This is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other resources on <a href=\"http:\/\/icl-f11.utcompling.com\/links\">the links page of the Computational Linguistics course<\/a> I\u2019m creating these for.&nbsp;Additionally you can find this and other tutorial series on the JCG <a href=\"http:\/\/www.javacodegeeks.com\/p\/java-tutorials.html\">Java Tutorials<\/a> page.<\/p>\n<p>Lists (and other sequence data structures, like Ranges and Arrays) allow you to group collections of objects in an ordered manner: you can access elements of a list by indexing their position in the list, or iterate over the list elements, one by one, using <strong>for<\/strong> expressions and sequence functions like <strong>map<\/strong>, <strong>filter<\/strong>, <strong>reduce<\/strong> and <strong>fold<\/strong>. Another important kind of data structure is the associative array, which you\u2019ll come to know in Scala as a <strong>Map<\/strong>. (Yes, this has the unfortunate ambiguity with the <strong>map<\/strong> <em>function<\/em>, but their use will be quite clear from context.) Maps allow you to store a collection of key-value pairs and to access the values by the keys associated with them, rather than via an index (as with a List).<\/p>\n<p>Example cases where you could use a Map:<\/p>\n<ul>\n<li>Associating English words with their German translations<\/li>\n<li>Associating each word with its count in a given text<\/li>\n<li>Associating each word with its possible parts-of-speech<\/li>\n<\/ul>\n<p>You\u2019ll see concrete examples of each of these in this post.<\/p>\n<h2>    Creating Maps and accessing their elements<\/h2>\n<p>Maps are quite intuitive to grasp. Here\u2019s an example with a few English words and their German translations. One easy way of creating a Map is by passing in a list of pairs, where the first element of each pair defines a key and the second defines a corresponding value.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val engToDeu = Map((\"dog\",\"Hund\"), (\"cat\",\"Katze\"), (\"rhinoceros\",\"Nashorn\"))\r\nengToDeu: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(dog -&gt; Hund, cat -&gt; Katze, rhinoceros -&gt; Nashorn)\r\n<\/pre>\n<p>Notice that the Map entries are of the form <em>key -&gt; value<\/em>. We may then retrieve the German translation for <em>dog<\/em> by providing the key \u201c<em>dog<\/em>\u201d to the Map we created.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu(\"dog\")\r\nres0: java.lang.String = Hund\r\n<\/pre>\n<p>Think for a moment what you would have to do to accomplish this with Lists. You\u2019d need need two Lists, one for each language, and they\u2019d need to be aligned so that each element in one list corresponded to its translation in the other list.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val engWords = List(\"dog\",\"cat\",\"rhinoceros\")\r\nengWords: List[java.lang.String] = List(dog, cat, rhinoceros)\r\n\r\nscala&gt; val deuWords = List(\"Hund\",\"Katze\",\"Nashorn\")\r\ndeuWords: List[java.lang.String] = List(Hund, Katze, Nashorn)\r\n<\/pre>\n<p>Then, to find the translation of <em>cat<\/em>, you would have to find the index of cat in <em>engWords<\/em>, and then look up that index in <em>deuWords<\/em>.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engWords.indexOf(\"cat\")\r\nres2: Int = 1\r\n\r\nscala&gt; deuWords(engWords.indexOf(\"cat\"))\r\nres3: java.lang.String = Katze\r\n<\/pre>\n<p>This is actually quite inefficient, as well as having other problems. Maps are the right thing for what we want here, and they do they job of retrieving values for keys quite efficiently.<\/p>\n<p>It turns out that we can take two lists that are aligned in this way and construct a Map very easily. Recall that zipping two lists together creates one list of pairs, where each pair gives the elements that shared the same index.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engWords.zip(deuWords)\r\nres4: List[(java.lang.String, java.lang.String)] = List((dog,Hund), (cat,Katze), (rhinoceros,Nashorn))\r\n<\/pre>\n<p>By calling the <strong>toMap<\/strong> method on such a List of pairs, we get a Map.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engWords.zip(deuWords).toMap\r\nres5: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(dog -&gt; Hund, cat -&gt; Katze, rhinoceros -&gt; Nashorn)\r\n<\/pre>\n<p>Note that even though the REPL is showing the order of the key-value pairs to be the same as the original list we constructed the map from, there is no inherent order to the elements of a Map.<\/p>\n<p>You can add elements to a Map to create a new Map using the <strong>+<\/strong> operator and an arrow <strong>-&gt;<\/strong> between each key and value pair.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu + \"owl\" -&gt; \"Eule\"\r\nres6: (java.lang.String, java.lang.String) = (Map(dog -&gt; Hund, cat -&gt; Katze, rhinoceros -&gt; Nashorn)owl,Eule)\r\n\r\nscala&gt; engToDeu + (\"owl\" -&gt; \"Eule\", \"hippopotamus\" -&gt; \"Nilpferd\")\r\nres7: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(rhinoceros -&gt; Nashorn, dog -&gt; Hund, owl -&gt; Eule, hippopotamus -&gt; Nilpferd, cat -&gt; Katze)\r\n<\/pre>\n<p>You can add one Map to another using the <strong>++<\/strong> operator.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val newEntries = Map((\"hippopotamus\", \"Nilpferd\"),(\"owl\",\"Eule\"))\r\nnewEntries: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(hippopotamus -&gt; Nilpferd, owl -&gt; Eule)\r\n\r\nscala&gt; val expandedEngToDeu = engToDeu ++ newEntries\r\nexpandedEngToDeu: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(rhinoceros -&gt; Nashorn, dog -&gt; Hund, owl -&gt; Eule, hippopotamus -&gt; Nilpferd, cat -&gt; Katze)\r\n<\/pre>\n<p>You can do the same by passing in a List of tuples to the ++ operator.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu ++ List((\"hippopotamus\", \"Nilpferd\"),(\"owl\",\"Eule\"))\r\nres8: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(rhinoceros -&gt; Nashorn, dog -&gt; Hund, owl -&gt; Eule, hippopotamus -&gt; Nilpferd, cat -&gt; Katze)\r\n<\/pre>\n<p>And you can remove a key from a Map with the \u2013 operator.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu - \"dog\"\r\nres9: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(cat -&gt; Katze, rhinoceros -&gt; Nashorn)\r\n<\/pre>\n<p>See<a href=\"http:\/\/www.scala-lang.org\/api\/current\/scala\/collection\/immutable\/Map.html\"> the Map API<\/a> for more examples of such functions. Note: throughout this post, I\u2019m sticking to immutable Maps \u2014 if you are looking at any other tutorials and are wondering why certain methods from those aren\u2019t working here, they may have been using mutable Maps, which we\u2019ll discuss later.<\/p>\n<p>If we ask for the value associated with a key that doesn\u2019t exist in the Map, we get an error.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu(\"bird\")\r\njava.util.NoSuchElementException: key not found: bird\r\nat scala.collection.MapLike$class.default(MapLike.scala:224)\r\n(etc.)\r\n<\/pre>\n<p>You can check for whether a key is in the Map using the <strong>contains<\/strong> method.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu.contains(\"bird\")\r\nres10: Boolean = false\r\n\r\nscala&gt; engToDeu.contains(\"dog\")\r\nres11: Boolean = true\r\n<\/pre>\n<p>Let\u2019s say you had a list of English words and wanted to look up their corresponding German words, and you want to protect yourself against the <strong>NoSuchElementException<\/strong>. One way to do this is to filter the words using <strong>contains<\/strong>, and then map the remaining ones through <em>engToDeu<\/em>.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val wordsToTranslate = List(\"dog\",\"bird\",\"cat\",\"armadillo\")\r\nwordsToTranslate: List[java.lang.String] = List(dog, bird, cat, armadillo)\r\n\r\nscala&gt; wordsToTranslate.filter(x=&gt;engToDeu.contains(x)).map(x=&gt;engToDeu(x))\r\nres12: List[java.lang.String] = List(Hund, Katze)\r\n<\/pre>\n<p>This is a useful ways of safely applying a Map to a list of items. However, we\u2019ll see a better way to deal with missing values later on, using Options.<\/p>\n<p>If you there is a sensible default value for any key you might try with your map, you can use the <strong>getOrElse<\/strong> method. You provide the key as the first argument, and then the default value as the second.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu.getOrElse(\"dog\",\"???\")\r\nres1: java.lang.String = Hund\r\n\r\nscala&gt; engToDeu.getOrElse(\"armadillo\",\"???\")\r\nres2: java.lang.String = ???\r\n<\/pre>\n<p>It is quite common to use <strong>getOrElse<\/strong> with a default of 0 for Maps that contain statistics, such as word counts (see below), where the absence of a key naturally indicates that it has, e.g., a count of zero.<\/p>\n<p>If you have a consistent default value for any keys that aren\u2019t in the Map, you can set it by using the withDefault method.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val engToDeu = Map((\"dog\",\"Hund\"), (\"cat\",\"Katze\"), (\"rhinoceros\",\"Nashorn\")).withDefault(x =&gt; \"???\")\r\nengToDeu: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(dog -&gt; Hund, cat -&gt; Katze, rhinoceros -&gt; Nashorn)\r\n\r\nscala&gt; engToDeu(\"armadillo\")\r\nres3: java.lang.String = ???\r\n<\/pre>\n<p>Now you can ask for values in the usual manner, without needing to use <strong>getOrElse<\/strong> and providing the default every time.<\/p>\n<h2>    Keys and values in Maps<\/h2>\n<p>You may have observed that Scala tells you more than that you have just created a Map. Like List, Map is a parameterized type, which means that it is a generic way of collecting a bunch of objects of particular types together. Above we saw an instance of a <strong>Map[String, String]<\/strong> (leaving off the <strong>java.lang<\/strong> part to make it clearer). The first String indicates that the <em>keys<\/em> are strings and the second that <em>values<\/em> are Strings. Basically, any type can be used in either position (<em>warning<\/em>: you should avoid using mutable data structures as keys unless you know what you are doing). Here are some examples (try to ignore the <strong>scala.collection.immutable<\/strong> and <strong>java.lang<\/strong> parts and just focus on the <strong>Map[X,Y]<\/strong> signatures we get).<\/p>\n<pre class=\"brush: scala;\">scala&gt; Map((10,\"ten\"), (100,\"one hundred\"))\r\nres0: scala.collection.immutable.Map[Int,java.lang.String] = Map(10 -&gt; ten, 100 -&gt; one hundred)\r\n\r\nscala&gt; Map((\"a\",1),(\"b\",2))\r\nres1: scala.collection.immutable.Map[java.lang.String,Int] = Map(a -&gt; 1, b -&gt; 2)\r\n\r\nscala&gt; Map((1,3.14), (2,6.28))\r\nres2: scala.collection.immutable.Map[Int,Double] = Map(1 -&gt; 3.14, 2 -&gt; 6.28)\r\n\r\nscala&gt; Map(((\"pi\",1),3.14), ((\"tau\",2),6.28))\r\nres3: scala.collection.immutable.Map[(java.lang.String, Int),Double] = Map((pi,1) -&gt; 3.14, (tau,2) -&gt; 6.28)\r\n\r\nscala&gt; Map((\"the\", List(\"Determiner\")), (\"book\", List(\"Verb\", \"Noun\")), (\"off\", List(\"Preposition\", \"Verb\")))\r\nres4: scala.collection.immutable.Map[java.lang.String, List[java.lang.String]] = Map(the -&gt; List(Determiner), book -&gt; List(Verb, Noun), off -&gt; List(Preposition, Verb))\r\n<\/pre>\n<p>The last two examples show some very useful aspects of key and values types that allow you to use more complex keys and values. The former uses a <strong>(String, Int)<\/strong> pair as a key, with signature <strong>Map[(String, Int), Double]<\/strong>, and the latter uses a <strong>List[String]<\/strong> as the value, with signature <strong>Map[String, List[String]]<\/strong>. So you can bundle together several types using tuples and you can use parameterized data structures to parameterize another data structure.<\/p>\n<h2>    A simple translation task<\/h2>\n<p>Here is a mini German\/English dictionary as a Map.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val miniDictionary = Map((\"befreit\", \"liberated\"), (\"baeche\", \"brooks\"), (\"eise\", \"ice\"), (\"sind\", \"are\"), (\"strom\", \"river\"), (\"und\", \"and\"), (\"vom\", \"from\"))\r\nminiDictionary: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(und -&gt; and, eise -&gt; ice, sind -&gt; are, befreit -&gt; liberated, strom -&gt; river, vom -&gt; from, baeche -&gt; brooks)\r\n<\/pre>\n<p>We can provide a (very bad) translation of the German sentence \u201c<em>vom eise befreit sind strom und baeche<\/em>\u201d using this dictionary: we simply split the German sentence and then map over its elements, looking up each word in the dictionary.<div style=\"display:inline-block; margin: 15px 0;\"> <div id=\"adngin-JavaCodeGeeks_incontent_video-0\" style=\"display:inline-block;\"><\/div> <\/div><\/p>\n<pre class=\"brush: scala;\">scala&gt; val example = \"vom eise befreit sind strom und baeche\"\r\nexample: java.lang.String = vom eise befreit sind strom und baeche\r\n\r\nscala&gt; example.split(\" \").map(deuWord =&gt; miniDictionary(deuWord)).mkString(\" \")\r\nres0: String = from ice liberated are river and brooks\r\n<\/pre>\n<p>Okay, not quite \u201cfrom the ice they are freed, the stream and brook\u201d but then again it\u2019s pretty much the dumbest machine translation approach available\u2026<\/p>\n<p>A danger of course is that we will have words that aren\u2019t in the dictionary, leading to an exception.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val example2 = \"vom eise befreit sind strom und schiffe\"\r\nexample2: java.lang.String = vom eise befreit sind strom und schiffe\r\n\r\nscala&gt; example2.split(\" \").map(deuWord =&gt; miniDictionary(deuWord)).mkString(\" \")\r\njava.util.NoSuchElementException: key not found: schiffe\r\n<\/pre>\n<p>We\u2019ll return to this below.<\/p>\n<h2>    Creating Maps from Lists using groupBy<\/h2>\n<p>We frequently have data stored in a particular data structure and would like to work with it using another data structure that organizes the data points in some other manner. Here, we\u2019ll look at how to convert a List into Map using the <strong>groupBy<\/strong> method in order to do some useful processing for working with parts-of-speech. We\u2019ll also see the <strong>Set<\/strong> data structure along the way.<\/p>\n<p>We\u2019ll start with a very basic example of what <strong>groupBy<\/strong> does. Given a list of number tokens, we can obtain a Map from the number types to all of the tokens of each number.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val numbers = List(1,4,5,1,6,5,2,8,1,9,2,1)\r\nnumbers: List[Int] = List(1, 4, 5, 1, 6, 5, 2, 8, 1, 9, 2, 1)\r\n\r\nscala&gt; numbers.groupBy(x=&gt;x)\r\nres19: scala.collection.immutable.Map[Int,List[Int]] = Map(5 -&gt; List(5, 5), 1 -&gt; List(1, 1, 1, 1), 6 -&gt; List(6), 9 -&gt; List(9), 2 -&gt; List(2, 2), 8 -&gt; List(8), 4 -&gt; List(4))\r\n<\/pre>\n<p>As you can see from the result, <strong>groupBy<\/strong> took the anonymous function <strong>x=&gt;x<\/strong>, grouped all of the elements of the List that have the same value of <em>x<\/em>, and then created a Map from each <em>x<\/em> to the group containing its tokens. So, we get 2 mapping to a List containing 2?s, and so on. This probably seems a bit weird, but it is incredibly useful when we consider Lists that have more interesting elements in them. To do so, let\u2019s go back to the part-of-speech tagging example from <a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-iteration-for.html\" title=\"First steps in Scala for beginning programmers, Part 4\">Part 4 of these tutorials<\/a>. Say we have a sentence that is tagged with parts of speech, such as the following (made up) example that ensures some tag ambiguities.<\/p>\n<div style=\"padding-left: 30px\"><em>in the dark , a tall man saw the saw that he needed to man to cut the dark tree .<\/em><\/div>\n<p>The parts-of-speech could be annotated as follows (with lots of simplifications, and apologies to any offense caused to anyone\u2019s linguistic sensitivities).<\/p>\n<div style=\"padding-left: 30px\">in\/Prep the\/Det dark\/Noun ,\/Punc a\/Det tall\/Adjective man\/Noun saw\/Verb the\/Det saw\/Noun that\/Pronoun he\/Pronoun needed\/Verb to\/Prep man\/Verb to\/Prep cut\/Verb the\/Det dark\/Adjective tree\/Noun .\/Punc<\/div>\n<p><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-iteration-for.html\" title=\"First steps in Scala for beginning programmers, Part 4\">See Part 4<\/a> for detailed explanation of how the following expression turns a string like this into a List of tuples.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val tagged = \"in\/Prep the\/Det dark\/Noun ,\/Punc a\/Det tall\/Adjective man\/Noun saw\/Verb the\/Det saw\/Noun that\/Pronoun he\/Pronoun needed\/Verb to\/Prep man\/Verb to\/Prep cut\/Verb the\/Det dark\/Adjective tree\/Noun .\/Punc\".split(\" \").toList.map(x =&gt; x.split(\"\/\")).map(x =&gt; (x(0), x(1)))\r\ntagged: List[(java.lang.String, java.lang.String)] = List((in,Prep), (the,Det), (dark,Noun), (,,Punc), (a,Det), (tall,Adjective), (man,Noun), (saw,Verb), (the,Det), (saw,Noun), (that,Pronoun), (he,Pronoun), (needed,Verb), (to,Prep), (man,Verb), (to,Prep), (cut,Verb), (the,Det), (dark,Adjective), (tree,Noun), (.,Punc))\r\n<\/pre>\n<p>Now, let\u2019s use <strong>groupBy<\/strong> in various ways on this. The first thing we might be interested in is seeing which parts of speech each word is associated with.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val groupedTagged = tagged.groupBy(x =&gt; x._1)\r\ngroupedTagged: scala.collection.immutable.Map[java.lang.String,List[(java.lang.String, java.lang.String)]] = Map(in -&gt; List((in,Prep)), needed -&gt; List((needed,Verb)), . -&gt; List((.,Punc)), cut -&gt; List((cut,Verb)), saw -&gt; List((saw,Verb), (saw,Noun)), a -&gt; List((a,Det)), man -&gt; List((man,Noun), (man,Verb)), that -&gt; List((that,Pronoun)), dark -&gt; List((dark,Noun), (dark,Adjective)), to -&gt; List((to,Prep), (to,Prep)), , -&gt; List((,,Punc)), tall -&gt; List((tall,Adjective)), he -&gt; List((he,Pronoun)), tree -&gt; List((tree,Noun)), the -&gt; List((the,Det), (the,Det), (the,Det)))\r\n<\/pre>\n<p>So, now you see that the keys in the Map constructed by <strong>groupBy<\/strong> are the words and the values are the groups of the original elements. You can then see that the anonymous function<strong> x =&gt; x._1<\/strong> provided to <strong>groupBy<\/strong> does two things: it specifies the part of the input elements that will group different items together and it specifies that that part of the input defines the key space.<\/p>\n<p>However, we don\u2019t quite have what we want, which is to have the set of parts of speech associated with each word. Instead we have a List of tuples, e.g.:<\/p>\n<pre class=\"brush: scala;\">scala&gt; groupedTagged(\"saw\")\r\nres21: List[(java.lang.String, java.lang.String)] = List((saw,Verb), (saw,Noun))\r\n<\/pre>\n<p>Focussing on just this for a moment, we can map this and produce a List with just the parts-of-speech, and then turn that List into a Set with the <strong>toSet<\/strong> method in order to get just the unique parts-of-speech.<\/p>\n<pre class=\"brush: scala;\">scala&gt; groupedTagged(\"saw\").map(x=&gt;x._2)\r\nres24: List[java.lang.String] = List(Verb, Noun)\r\n\r\nscala&gt; groupedTagged(\"saw\").map(x=&gt;x._2).toSet\r\nres25: scala.collection.immutable.Set[java.lang.String] = Set(Verb, Noun)\r\n<\/pre>\n<p>Converting the List to a Set didn\u2019t do much here, but consider <em>the<\/em>, which has multiple tokens with the same part-of-speech.<\/p>\n<pre class=\"brush: scala;\">scala&gt; groupedTagged(\"the\")\r\nres26: List[(java.lang.String, java.lang.String)] = List((the,Det), (the,Det), (the,Det))\r\n\r\nscala&gt; groupedTagged(\"the\").map(x=&gt;x._2)\r\nres27: List[java.lang.String] = List(Det, Det, Det)\r\n\r\nscala&gt; groupedTagged(\"the\").map(x=&gt;x._2).toSet\r\nres28: scala.collection.immutable.Set[java.lang.String] = Set(Det)\r\n<\/pre>\n<p>Sets are yet another of the useful data structures you have to work with, along with Maps and Lists. They work just like you would expect Sets to: they contain a collection of unique, unordered elements, and they allow you to see whether an element is in the set, whether one set is a subset of another, iterate over their elements, etc.<\/p>\n<p>Now, back to getting from the word\/tag pairs to a mapping from words to possible tags for each word. The keys we got from <strong>tagged.groupBy(x =&gt; x._1) <\/strong> are what we want, but we want to transform the values from Lists of word\/tag tokens to Sets of tags, which we can do with the <strong>mapValues<\/strong> method on Maps.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val wordsToTags = tagged.groupBy(x =&gt; x._1).mapValues(listOfWordTagPairs =&gt; listOfWordTagPairs.map(wordTagPair =&gt; wordTagPair._2).toSet)\r\nwordsToTags: scala.collection.immutable.Map[java.lang.String,scala.collection.immutable.Set[java.lang.String]] = Map(in -&gt; Set(Prep), needed -&gt; Set(Verb), . -&gt; Set(Punc), cut -&gt; Set(Verb), saw -&gt; Set(Verb, Noun), a -&gt; Set(Det), man -&gt; Set(Noun, Verb), that -&gt; Set(Pronoun), dark -&gt; Set(Noun, Adjective), to -&gt; Set(Prep), , -&gt; Set(Punc), tall -&gt; Set(Adjective), he -&gt; Set(Pronoun), tree -&gt; Set(Noun), the -&gt; Set(Det))\r\n<\/pre>\n<p>The bit inside the <strong>mapValues(\u2026)<\/strong> part will have some readers scrunching up their eyes, but you just need to look at the line where we got <span style=\"text-decoration: underline\">res28<\/span> above: if you understood that, then you just need to realize we are doing exactly the same thing, but now in the context of mapping over the values rather than dealing with a single value. Now you know how to map over values that you are mapping over.<\/p>\n<p>Now that it is hand, we can easily query the <em>wordsToTags<\/em> Map to see whether various words have various tags.<\/p>\n<pre class=\"brush: scala;\">scala&gt; wordsToTags(\"man\")(\"Noun\")\r\nres8: Boolean = true\r\n\r\nscala&gt; wordsToTags(\"man\")(\"Det\")\r\nres9: Boolean = false\r\n\r\nscala&gt; wordsToTags(\"man\")(\"Verb\")\r\nres10: Boolean = true\r\n\r\nscala&gt; wordsToTags(\"saw\")(\"Verb\")\r\nres11: Boolean = true\r\n<\/pre>\n<p>This is an example of how data structures within data structures (here Sets within a Map) are quite useful. (<em>Exercise<\/em>: think about what a tree is for a moment and how you might implement it using Lists.)<\/p>\n<p>There are a variety of things you can do in computational linguistics with Maps from words to their parts-of-speech. A simple example is to compute the average number of tags per word type.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val avgTagsPerType = wordsToTags.values.map(x=&gt;x.size).sum\/wordsToTags.size.toDouble\r\navgTagsPerType: Double = 1.2\r\n<\/pre>\n<p>If it isn\u2019t clear to you what is going on here, tease it apart in your own REPL!<\/p>\n<p>We can turn our word\/tag pairs the other way to find out which words go with each part-of-speech. The only thing we need to do is <strong>groupBy<\/strong> on the second element of each pair, and then map the List values to their first element and get a Set from those.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val tagsToWords = tagged.groupBy(x =&gt; x._2).mapValues(listOfWordTagPairs =&gt; listOfWordTagPairs.map(wordTagPair =&gt; wordTagPair._1).toSet)\r\ntagsToWords: scala.collection.immutable.Map[java.lang.String,scala.collection.immutable.Set[java.lang.String]] = Map(Prep -&gt; Set(in, to), Det -&gt; Set(the, a), Noun -&gt; Set(dark, man, saw, tree), Pronoun -&gt; Set(that, he), Verb -&gt; Set(saw, needed, man, cut), Punc -&gt; Set(,, .), Adjective -&gt; Set(tall, dark))\r\n<\/pre>\n<p>This basic paradigm is a powerful one for flipping between different data structures depending on what our needs are. It also demonstrates several important concepts with working with Lists, Maps and Sets. The next section shows a simple application of this idea for counting words in a text.<\/p>\n<h2>    Counting words<\/h2>\n<p>A common task in computational linguistics is to calculate word statistics, and the most basic of those is to count the number of tokens of each word type in a particular text. The most common way to store and access those counts is in a Map, but how do you create such a Map from a given text? If we look at a text as a list of strings, then the <strong>groupBy<\/strong> paradigm we did above gives us exactly what we need \u2014 in fact it is even simpler than the word\/tag manipulations done above.<\/p>\n<p>The example text we\u2019ll use is the tongue-twister about woodchucks.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val woodchuck = \"how much wood could a woodchuck chuck if a woodchuck could chuck wood ? as much wood as a woodchuck would , if a woodchuck could chuck wood .\"\r\nwoodchuck: java.lang.String = how much wood could a woodchuck chuck if a woodchuck could chuck wood ? as much wood as a woodchuck would , if a woodchuck could chuck wood .\r\n<\/pre>\n<p>Given this, here\u2019s how we can compute the number of occurrences of each word type. First we <strong>groupBy<\/strong> on the elements. Though a list of strings isn\u2019t as interesting as having a list of Tuples as we had with words and tags, it still produces a useful result: we now have a unique set of keys corresponding to the types of elements found in the Array, and there is a corresponding value to each one that is the Array of tokens of that type.<\/p>\n<pre class=\"brush: scala;\">scala&gt; woodchuck.split(\" \").groupBy(x=&gt;x)\r\nres29: scala.collection.immutable.Map[java.lang.String,Array[java.lang.String]] = Map(woodchuck -&gt; Array(woodchuck, woodchuck, woodchuck, woodchuck), chuck -&gt; Array(chuck, chuck, chuck), . -&gt; Array(.), would -&gt; Array(would), if -&gt; Array(if, if), a -&gt; Array(a, a, a, a), as -&gt; Array(as, as), , -&gt; Array(,), how -&gt; Array(how), much -&gt; Array(much, much), wood -&gt; Array(wood, wood, wood, wood), ? -&gt; Array(?), could -&gt; Array(could, could, could))\r\n<\/pre>\n<p>And, we want to do something much simpler than what we did with the part-of-speech example: we just need to count the length of each list, since they each contain every token of the corresponding word type. The function passed to <strong>mapValues<\/strong> is thus quite a bit simpler than the ones given in the previous section.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val counts = woodchuck.split(\" \").groupBy(x=&gt;x).mapValues(x=&gt;x.length)\r\ncounts: scala.collection.immutable.Map[java.lang.String,Int] = Map(woodchuck -&gt; 4, chuck -&gt; 3, . -&gt; 1, would -&gt; 1, if -&gt; 2, a -&gt; 4, as -&gt; 2, , -&gt; 1, how -&gt; 1, much -&gt; 2, wood -&gt; 4, ? -&gt; 1, could -&gt; 3)\r\n<\/pre>\n<p>With <em>counts<\/em>, we can now access the frequencies of any of the words that were in the text.<\/p>\n<pre class=\"brush: scala;\">scala&gt; counts(\"woodchuck\")\r\nres5: Int = 4\r\n\r\nscala&gt; counts(\"could\")\r\nres6: Int = 3\r\n<\/pre>\n<p>Easy!  Of course, we normally want to build word counts for texts that are longer and are stored in a file rather than explicitly added to Scala code. The next tutorial will demonstrate how to do that.<\/p>\n<h2>    Iterating over the keys and values in a Map<\/h2>\n<p>The material above shows some useful aspects of Maps, but of course there is much more you can do with them, often requiring iterating through the key-value pairs in the Map. We\u2019ll use the <em>counts<\/em> Map created above for demonstrating this.<\/p>\n<p>You can access just the keys, or just the values.<\/p>\n<pre class=\"brush: scala;\">scala&gt; counts.keys\r\nres0: Iterable[java.lang.String] = Set(woodchuck, chuck, ., would, if, a, as, ,, how, much, wood, ?, could)\r\n\r\nscala&gt; counts.values\r\nres1: Iterable[Int] = MapLike(4, 3, 1, 1, 2, 4, 2, 1, 1, 2, 4, 1, 3)\r\n<\/pre>\n<p>Notice that these are both Iterable data structures, so we can do all of the usual mapping, filtering, and so on, that we have already done with lists. (You may convert them to Lists if you like using <strong>toList<\/strong>, of course.)<\/p>\n<p>You can print out all of the key -&gt; value pairs in the Map in a number of ways. One is to use a for expression.<\/p>\n<pre class=\"brush: scala;\">scala&gt; for ((k,v) &lt;- counts) println(k + \" -&gt; \" + v)\r\nwoodchuck -&gt; 4\r\nchuck -&gt; 3\r\n. -&gt; 1\r\nwould -&gt; 1\r\nif -&gt; 2\r\na -&gt; 4\r\nas -&gt; 2\r\n, -&gt; 1\r\nhow -&gt; 1\r\nmuch -&gt; 2\r\nwood -&gt; 4\r\n? -&gt; 1\r\ncould -&gt; 3\r\n<\/pre>\n<p>And here are other ways to achieve the same result (output omitted since it is the same).<\/p>\n<pre class=\"brush: scala;\">for (k &lt;- counts.keys) println(k + \" -&gt; \" + counts(k))\r\ncounts.map(kvPair =&gt; kvPair._1 + \" -&gt; \" + kvPair._2).foreach(println)\r\ncounts.keys.map(k =&gt; k + \" -&gt; \" + counts(k)).foreach(println)\r\ncounts.foreach { case(k,v) =&gt; println(k + \" -&gt; \" + v) }\r\ncounts.foreach(kvPair =&gt; println(kvPair._1 + \" -&gt; \" + kvPair._2))\r\n<\/pre>\n<p>And so on. Basically, you are able to step through the Map one key-value pair at a time, or you can grab the set of keys and then step through those and access the values from the map. Which form you use depends on what you need \u2014 for example, the <strong>foreach<\/strong> construct doesn\u2019t return a value, but the <strong>for<\/strong> expressions and the <strong>map<\/strong> expressions do return values. Why would you do that? Well, as an example, consider grouping all words that have occurred the same number of times.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val countsToWords = counts.keys.toList.map(k =&gt; (counts(k),k)).groupBy(x=&gt;x._1).mapValues(x=&gt;x.map(y=&gt;y._2))\r\ncountsToWords: scala.collection.immutable.Map[Int,List[java.lang.String]] = Map(3 -&gt; List(chuck, could), 4 -&gt; List(woodchuck, a, wood), 1 -&gt; List(., would, ,, how, ?), 2 -&gt; List(if, as, much))\r\n<\/pre>\n<p>We go from a Map to a Set of its keys to a List of those keys to a List of Tuples of the values and the keys to a Map from the values of the original Map to such Tuples, and then we map the values of the new map to just contain the words (the original keys). (That\u2019s a mouthful, so try each step in the REPL to see what is going on in detail.)<\/p>\n<p>Now we can output <em>countsToWords<\/em> sorted in descending numerical order by count, and then by alphabetical order by word within each count.<\/p>\n<pre class=\"brush: scala;\">scala&gt; countsToWords.keys.toList.sorted.reverse.foreach(x =&gt; println(x + \": \" + countsToWords(x).sorted.mkString(\",\")))\r\n4: a,wood,woodchuck\r\n3: chuck,could\r\n2: as,if,much\r\n1: ,,.,?,how,would\r\n<\/pre>\n<h2>    Options and flatMapping for dealing with missing keys<\/h2>\n<p>I pointed out toward the start of this tutorial that we run into trouble if we ask for a key that doesn\u2019t exist in a Map. Let\u2019s go back to the <em>engToDeu<\/em> Map we began with.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val engToDeu = Map((\"dog\",\"Hund\"), (\"cat\",\"Katze\"), (\"rhinoceros\",\"Nashorn\"))\r\nengToDeu: scala.collection.immutable.Map[java.lang.String,java.lang.String] = Map(dog -&gt; Hund, cat -&gt; Katze, rhinoceros -&gt; Nashorn)\r\n\r\nscala&gt; engToDeu(\"dog\")\r\nres0: java.lang.String = Hund\r\n\r\nscala&gt; engToDeu(\"bird\")\r\njava.util.NoSuchElementException: key not found: bird\r\n<\/pre>\n<p>There is another way of accessing the elements of a Map, using the <strong>get<\/strong> method.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu.get(\"dog\")\r\nres2: Option[java.lang.String] = Some(Hund)\r\n\r\nscala&gt; engToDeu.get(\"bird\")\r\nres3: Option[java.lang.String] = None\r\n<\/pre>\n<p>Now, the return value is an <strong>Option[String]<\/strong>. An <strong>Option<\/strong> is either a <strong>Some<\/strong> that contains a value or a <strong>None<\/strong>, which means there is no value. If you want to get the value out of a Some, you use the <strong>get<\/strong> method on Options.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val dogTrans = engToDeu.get(\"dog\")\r\ndogTrans: Option[java.lang.String] = Some(Hund)\r\n\r\nscala&gt; dogTrans.get\r\nres4: java.lang.String = Hund\r\n<\/pre>\n<p>If you just use <strong>get<\/strong> on a Map to obtain an Option and then immediately call <strong>get<\/strong> on the Option, we get the same behavior we had before.<\/p>\n<pre class=\"brush: scala;\">scala&gt; engToDeu.get(\"dog\").get\r\nres6: java.lang.String = Hund\r\n\r\nscala&gt; engToDeu.get(\"bird\").get\r\njava.util.NoSuchElementException: None.get\r\n<\/pre>\n<p>So, at this point, you are probably thinking that this sounds like a waste of time that is just making things more complex. Wait! It actually is tremendously useful because of pattern matching and the way many methods on sequences work.<\/p>\n<p>First, here is how you can write a protected form of translating the words in a list without getting an exception.<\/p>\n<pre class=\"brush: scala;\">scala&gt; wordsToTranslate.foreach { x =&gt; engToDeu.get(x) match {\r\n|   case Some(y) =&gt; println(x + \" -&gt; \" + y)\r\n|   case None =&gt;\r\n| }}\r\ndog -&gt; Hund\r\ncat -&gt; Katze\r\n<\/pre>\n<p>I know\u2026 this probably still isn\u2019t convincing \u2014 it still looks more involved than the conditional we used (far) above to check whether <em>engToDeu<\/em> contained a given key (at least for this particular example). Hold on\u2026 because now we are just about ready for things to get simpler, and learn some useful things about Lists in doing so.<\/p>\n<p>First, you should know about a great method on Lists called <strong>flatten<\/strong>. If you have a List of Lists of Strings, you can use <strong>flatten<\/strong> to get a single List of Strings. Consider the following example, in which we flatten a List of Lists of Strings and make a single String out of the result with <strong>mkString<\/strong>. Notice that the empty List in the third spot of the main List just disappears when we flatten it.<\/p>\n<pre class=\"brush: scala;\">scala&gt; val sentences = List(List(\"Here\",\"is\",\"sentence\",\"one\",\".\"), List(\"The\",\"third\",\"sentence\",\"is\",\"empty\",\"!\"), List(),List(\"Lastly\",\",\",\"we\",\"have\",\"a\",\"final\",\"sentence\",\".\"))\r\nsentences: List[List[java.lang.String]] = List(List(Here, is, sentence, one, .), List(The, third, sentence, is, empty, !), List(), List(Lastly, ,, we, have, a, final, sentence, .))\r\n\r\nscala&gt; sentences.flatten\r\nres0: List[java.lang.String] = List(Here, is, sentence, one, ., The, third, sentence, is, empty, !, Lastly, ,, we, have, a, final, sentence, .)\r\n\r\nscala&gt; sentences.flatten.mkString(\" \")\r\nres1: String = Here is sentence one . The third sentence is empty ! Lastly , we have a final sentence .\r\n<\/pre>\n<p>Flattening in general is pretty useful in its own right. Where it comes to play with Option values is that Options can be thought of a Lists: Somes are like one element Lists and Nones are like empty Lists. So, when you have a List of Options, the flatten method gives you the value in a Some and any Nones just drop away.<\/p>\n<pre class=\"brush: scala;\">scala&gt; wordsToTranslate.map(x =&gt; engToDeu.get(x))\r\nres12: List[Option[java.lang.String]] = List(Some(Hund), None, Some(Katze), None)\r\n\r\nscala&gt; wordsToTranslate.map(x =&gt; engToDeu.get(x)).flatten\r\nres13: List[java.lang.String] = List(Hund, Katze)\r\n<\/pre>\n<p>This is such a generally useful paradigm that there is a function <strong>flatMap<\/strong> which does exactly this.<\/p>\n<pre class=\"brush: scala;\">scala&gt; wordsToTranslate.flatMap(x =&gt; engToDeu.get(x))\r\nres14: List[java.lang.String] = List(Hund, Katze)\r\n<\/pre>\n<p>So, returning to the translation example above, we can now safely skip on by \u201c<em>schiffe<\/em>\u201d without fuss.<\/p>\n<pre class=\"brush: scala;\">scala&gt; example2.split(\" \").flatMap(deuWord =&gt; miniDictionary.get(deuWord)).mkString(\" \")\r\nres15: String = from ice liberated are river and\r\n<\/pre>\n<p>Whether this is the desired behavior in this particular case is another question (e.g. you really should be doing some special unknown word handling). Nonetheless, you\u2019ll find that <strong>flatMap<\/strong> is quite handy in general for this sort of pattern, in which a list of elements is used to retrieve values from a Map that will be missing some of those values.<\/p>\n<p>An example of the further use of Options and <strong>flatMap<\/strong> is that you also may create functions that return Options and are thus amenable to flatMapping. Consider a function that squares only odd numbers and throws evens away (<em>note<\/em>: the % operator is the modulo operator that finds the remainder of division of one number by another \u2014 try it in the REPL).<\/p>\n<pre class=\"brush: scala;\">scala&gt; def squareOddNumber (x: Int) = if (x % 2 != 0) Some(x*x) else None\r\nsquareOddNumber: (x: Int)Option[Int]\r\n<\/pre>\n<p>If you <strong>map<\/strong> over the numbers 1 to 10, you\u2019ll see the Somes and Nones, and if you <strong>flatMap<\/strong> it, you get exactly the desired result of the squares of all the odd numbers without any pollution from the evens.<\/p>\n<pre class=\"brush: scala;\">scala&gt; (1 to 10).toList.map(x=&gt;squareOddNumber(x))\r\nres16: List[Option[Int]] = List(Some(1), None, Some(9), None, Some(25), None, Some(49), None, Some(81), None)\r\n\r\nscala&gt; (1 to 10).toList.flatMap(x=&gt;squareOddNumber(x))\r\nres17: List[Int] = List(1, 9, 25, 49, 81)\r\n<\/pre>\n<p>This turns out to be amazingly useful and common, so much so that the expression \u201c<a href=\"http:\/\/legendofklang.spreadshirt.se\/men-s-legendofklang-flatmap-that-sh-t-A15944995\">just flatMap that shit<\/a>\u201d has become a common refrain among Scala programmers. <a href=\"https:\/\/gist.github.com\/1090775\">Scala programmers even write scripts to remind them to do it.<\/a> :)<\/p>\n<p><strong><i>Reference: <\/i><\/strong><a href=\"http:\/\/bcomposes.wordpress.com\/2011\/09\/12\/first-steps-in-scala-for-beginning-programmers-part-7\/\">First steps in Scala for beginning programmers, Part 7<\/a> from our <a href=\"http:\/\/www.javacodegeeks.com\/p\/jcg.html\">JCG partner<\/a> Jason Baldridge at the <a href=\"http:\/\/bcomposes.wordpress.com\/\">Bcomposes<\/a> blog.<\/p>\n<p><strong><i>Related Articles :<\/i><\/strong><\/p>\n<ul>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/09\/scala-tutorial-scala-repl-expressions.html\">Scala Tutorial &#8211; Scala REPL, expressions, variables, basic types, simple functions, saving and running programs, comments<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/09\/scala-tutorial-tuples-lists-methods-on.html\">Scala Tutorial &#8211; Tuples, Lists, methods on Lists and Strings<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/09\/scala-tutorial-conditional-execution.html\">Scala Tutorial &#8211; conditional execution with if-else blocks and matching<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-iteration-for.html\">Scala Tutorial &#8211; iteration, for expressions, yield, map, filter, count<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-regular-expressions.html\">Scala Tutorial &#8211; regular expressions, matching<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-regular-expressions_05.html\">Scala Tutorial &#8211; regular expressions, matching and substitutions with the scala.util.matching API<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-scalaiosource-accessing.html\">Scala Tutorial &#8211; scala.io.Source, accessing files, flatMap, mutable Maps<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-objects-classes.html\">Scala Tutorial &#8211; objects, classes, inheritance, traits, Lists with multiple related types, apply<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-scripting-compiling-main.html\">Scala Tutorial &#8211; scripting, compiling, main methods, return values of functions<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/11\/scala-tutorial-sbt-scalabha-packages.html\">Scala Tutorial &#8211; SBT, scalabha, packages, build systems<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/11\/scala-tutorial-code-blocks-coding-style.html\">Scala Tutorial &#8211; code blocks, coding style, closures, scala documentation project<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/09\/fun-with-function-composition-in-scala.html\">Fun with function composition in Scala<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/08\/how-scala-changed-way-i-think-about-my.html\">How Scala changed the way I think about my Java Code<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2011\/09\/testing-with-scala.html\">Testing with Scala<\/a><\/li>\n<li><a href=\"http:\/\/www.javacodegeeks.com\/2010\/12\/things-every-programmer-should-know.html\">Things Every Programmer Should Know<\/a><\/li>\n<\/ul>\n<\/div>\n","protected":false},"excerpt":{"rendered":"<p>Preface This is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other resources on the links page of the Computational Linguistics course I\u2019m creating these for.&nbsp;Additionally you can find this and other tutorial series on the JCG Java Tutorials &hellip;<\/p>\n","protected":false},"author":67,"featured_media":227,"comment_status":"open","ping_status":"closed","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[20],"tags":[235],"class_list":["post-644","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-scala","tag-scala-tutorial"],"yoast_head":"<!-- This site is optimized with the Yoast SEO plugin v27.5 - https:\/\/yoast.com\/product\/yoast-seo-wordpress\/ -->\n<title>Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks<\/title>\n<meta name=\"description\" content=\"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other\" \/>\n<meta name=\"robots\" content=\"index, follow, max-snippet:-1, max-image-preview:large, max-video-preview:-1\" \/>\n<link rel=\"canonical\" href=\"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html\" \/>\n<meta property=\"og:locale\" content=\"en_US\" \/>\n<meta property=\"og:type\" content=\"article\" \/>\n<meta property=\"og:title\" content=\"Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks\" \/>\n<meta property=\"og:description\" content=\"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other\" \/>\n<meta property=\"og:url\" content=\"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html\" \/>\n<meta property=\"og:site_name\" content=\"Java Code Geeks\" \/>\n<meta property=\"article:publisher\" content=\"https:\/\/www.facebook.com\/javacodegeeks\" \/>\n<meta property=\"article:published_time\" content=\"2011-10-06T17:06:00+00:00\" \/>\n<meta property=\"article:modified_time\" content=\"2012-10-21T20:31:48+00:00\" \/>\n<meta property=\"og:image\" content=\"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg\" \/>\n\t<meta property=\"og:image:width\" content=\"150\" \/>\n\t<meta property=\"og:image:height\" content=\"150\" \/>\n\t<meta property=\"og:image:type\" content=\"image\/jpeg\" \/>\n<meta name=\"author\" content=\"Jason Baldridge\" \/>\n<meta name=\"twitter:card\" content=\"summary_large_image\" \/>\n<meta name=\"twitter:creator\" content=\"@http:\/\/twitter.com\/jasonbaldridge\" \/>\n<meta name=\"twitter:site\" content=\"@javacodegeeks\" \/>\n<meta name=\"twitter:label1\" content=\"Written by\" \/>\n\t<meta name=\"twitter:data1\" content=\"Jason Baldridge\" \/>\n\t<meta name=\"twitter:label2\" content=\"Est. reading time\" \/>\n\t<meta name=\"twitter:data2\" content=\"29 minutes\" \/>\n<script type=\"application\/ld+json\" class=\"yoast-schema-graph\">{\"@context\":\"https:\\\/\\\/schema.org\",\"@graph\":[{\"@type\":\"Article\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#article\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html\"},\"author\":{\"name\":\"Jason Baldridge\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/95ef2670a4040b0f7101c48dba2795c0\"},\"headline\":\"Scala Tutorial &#8211; Maps, Sets, groupBy, Options, flatten, flatMap\",\"datePublished\":\"2011-10-06T17:06:00+00:00\",\"dateModified\":\"2012-10-21T20:31:48+00:00\",\"mainEntityOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html\"},\"wordCount\":3553,\"commentCount\":2,\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/scala-logo.jpg\",\"keywords\":[\"Scala Tutorial\"],\"articleSection\":[\"Scala\"],\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"CommentAction\",\"name\":\"Comment\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#respond\"]}]},{\"@type\":\"WebPage\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html\",\"name\":\"Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks\",\"isPartOf\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\"},\"primaryImageOfPage\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#primaryimage\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#primaryimage\"},\"thumbnailUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/scala-logo.jpg\",\"datePublished\":\"2011-10-06T17:06:00+00:00\",\"dateModified\":\"2012-10-21T20:31:48+00:00\",\"description\":\"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other\",\"breadcrumb\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#breadcrumb\"},\"inLanguage\":\"en-US\",\"potentialAction\":[{\"@type\":\"ReadAction\",\"target\":[\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html\"]}]},{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#primaryimage\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/scala-logo.jpg\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2012\\\/10\\\/scala-logo.jpg\",\"width\":150,\"height\":150},{\"@type\":\"BreadcrumbList\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/2011\\\/10\\\/scala-tutorial-maps-sets-groupby.html#breadcrumb\",\"itemListElement\":[{\"@type\":\"ListItem\",\"position\":1,\"name\":\"Home\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\"},{\"@type\":\"ListItem\",\"position\":2,\"name\":\"JVM Languages\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/jvm-languages\"},{\"@type\":\"ListItem\",\"position\":3,\"name\":\"Scala\",\"item\":\"https:\\\/\\\/www.javacodegeeks.com\\\/category\\\/jvm-languages\\\/scala\"},{\"@type\":\"ListItem\",\"position\":4,\"name\":\"Scala Tutorial &#8211; Maps, Sets, groupBy, Options, flatten, flatMap\"}]},{\"@type\":\"WebSite\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#website\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"name\":\"Java Code Geeks\",\"description\":\"Java Developers Resource Center\",\"publisher\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\"},\"alternateName\":\"JCG\",\"potentialAction\":[{\"@type\":\"SearchAction\",\"target\":{\"@type\":\"EntryPoint\",\"urlTemplate\":\"https:\\\/\\\/www.javacodegeeks.com\\\/?s={search_term_string}\"},\"query-input\":{\"@type\":\"PropertyValueSpecification\",\"valueRequired\":true,\"valueName\":\"search_term_string\"}}],\"inLanguage\":\"en-US\"},{\"@type\":\"Organization\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#organization\",\"name\":\"Exelixis Media P.C.\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/\",\"logo\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\",\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"contentUrl\":\"https:\\\/\\\/www.javacodegeeks.com\\\/wp-content\\\/uploads\\\/2022\\\/06\\\/exelixis-logo.png\",\"width\":864,\"height\":246,\"caption\":\"Exelixis Media P.C.\"},\"image\":{\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/logo\\\/image\\\/\"},\"sameAs\":[\"https:\\\/\\\/www.facebook.com\\\/javacodegeeks\",\"https:\\\/\\\/x.com\\\/javacodegeeks\"]},{\"@type\":\"Person\",\"@id\":\"https:\\\/\\\/www.javacodegeeks.com\\\/#\\\/schema\\\/person\\\/95ef2670a4040b0f7101c48dba2795c0\",\"name\":\"Jason Baldridge\",\"image\":{\"@type\":\"ImageObject\",\"inLanguage\":\"en-US\",\"@id\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g\",\"url\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g\",\"contentUrl\":\"https:\\\/\\\/secure.gravatar.com\\\/avatar\\\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g\",\"caption\":\"Jason Baldridge\"},\"sameAs\":[\"http:\\\/\\\/bcomposes.wordpress.com\\\/\",\"http:\\\/\\\/www.linkedin.com\\\/pub\\\/jason-baldridge\\\/5\\\/629\\\/9b2\",\"https:\\\/\\\/x.com\\\/http:\\\/\\\/twitter.com\\\/jasonbaldridge\"],\"url\":\"https:\\\/\\\/www.javacodegeeks.com\\\/author\\\/jason-baldridge\"}]}<\/script>\n<!-- \/ Yoast SEO plugin. -->","yoast_head_json":{"title":"Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks","description":"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other","robots":{"index":"index","follow":"follow","max-snippet":"max-snippet:-1","max-image-preview":"max-image-preview:large","max-video-preview":"max-video-preview:-1"},"canonical":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html","og_locale":"en_US","og_type":"article","og_title":"Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks","og_description":"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other","og_url":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html","og_site_name":"Java Code Geeks","article_publisher":"https:\/\/www.facebook.com\/javacodegeeks","article_published_time":"2011-10-06T17:06:00+00:00","article_modified_time":"2012-10-21T20:31:48+00:00","og_image":[{"width":150,"height":150,"url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg","type":"image\/jpeg"}],"author":"Jason Baldridge","twitter_card":"summary_large_image","twitter_creator":"@http:\/\/twitter.com\/jasonbaldridge","twitter_site":"@javacodegeeks","twitter_misc":{"Written by":"Jason Baldridge","Est. reading time":"29 minutes"},"schema":{"@context":"https:\/\/schema.org","@graph":[{"@type":"Article","@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#article","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html"},"author":{"name":"Jason Baldridge","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/95ef2670a4040b0f7101c48dba2795c0"},"headline":"Scala Tutorial &#8211; Maps, Sets, groupBy, Options, flatten, flatMap","datePublished":"2011-10-06T17:06:00+00:00","dateModified":"2012-10-21T20:31:48+00:00","mainEntityOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html"},"wordCount":3553,"commentCount":2,"publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg","keywords":["Scala Tutorial"],"articleSection":["Scala"],"inLanguage":"en-US","potentialAction":[{"@type":"CommentAction","name":"Comment","target":["https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#respond"]}]},{"@type":"WebPage","@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html","url":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html","name":"Scala Tutorial - Maps, Sets, groupBy, Options, flatten, flatMap - Java Code Geeks","isPartOf":{"@id":"https:\/\/www.javacodegeeks.com\/#website"},"primaryImageOfPage":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#primaryimage"},"image":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#primaryimage"},"thumbnailUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg","datePublished":"2011-10-06T17:06:00+00:00","dateModified":"2012-10-21T20:31:48+00:00","description":"PrefaceThis is part 7 of tutorials for first-time programmers getting into Scala. Other posts are on this blog, and you can get links to those and other","breadcrumb":{"@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#breadcrumb"},"inLanguage":"en-US","potentialAction":[{"@type":"ReadAction","target":["https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html"]}]},{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#primaryimage","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2012\/10\/scala-logo.jpg","width":150,"height":150},{"@type":"BreadcrumbList","@id":"https:\/\/www.javacodegeeks.com\/2011\/10\/scala-tutorial-maps-sets-groupby.html#breadcrumb","itemListElement":[{"@type":"ListItem","position":1,"name":"Home","item":"https:\/\/www.javacodegeeks.com\/"},{"@type":"ListItem","position":2,"name":"JVM Languages","item":"https:\/\/www.javacodegeeks.com\/category\/jvm-languages"},{"@type":"ListItem","position":3,"name":"Scala","item":"https:\/\/www.javacodegeeks.com\/category\/jvm-languages\/scala"},{"@type":"ListItem","position":4,"name":"Scala Tutorial &#8211; Maps, Sets, groupBy, Options, flatten, flatMap"}]},{"@type":"WebSite","@id":"https:\/\/www.javacodegeeks.com\/#website","url":"https:\/\/www.javacodegeeks.com\/","name":"Java Code Geeks","description":"Java Developers Resource Center","publisher":{"@id":"https:\/\/www.javacodegeeks.com\/#organization"},"alternateName":"JCG","potentialAction":[{"@type":"SearchAction","target":{"@type":"EntryPoint","urlTemplate":"https:\/\/www.javacodegeeks.com\/?s={search_term_string}"},"query-input":{"@type":"PropertyValueSpecification","valueRequired":true,"valueName":"search_term_string"}}],"inLanguage":"en-US"},{"@type":"Organization","@id":"https:\/\/www.javacodegeeks.com\/#organization","name":"Exelixis Media P.C.","url":"https:\/\/www.javacodegeeks.com\/","logo":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/","url":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","contentUrl":"https:\/\/www.javacodegeeks.com\/wp-content\/uploads\/2022\/06\/exelixis-logo.png","width":864,"height":246,"caption":"Exelixis Media P.C."},"image":{"@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/logo\/image\/"},"sameAs":["https:\/\/www.facebook.com\/javacodegeeks","https:\/\/x.com\/javacodegeeks"]},{"@type":"Person","@id":"https:\/\/www.javacodegeeks.com\/#\/schema\/person\/95ef2670a4040b0f7101c48dba2795c0","name":"Jason Baldridge","image":{"@type":"ImageObject","inLanguage":"en-US","@id":"https:\/\/secure.gravatar.com\/avatar\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g","url":"https:\/\/secure.gravatar.com\/avatar\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g","contentUrl":"https:\/\/secure.gravatar.com\/avatar\/b755d282f869512990e0ce9118c71ccd859fad42163f8e5d62d180ea42ea9720?s=96&d=mm&r=g","caption":"Jason Baldridge"},"sameAs":["http:\/\/bcomposes.wordpress.com\/","http:\/\/www.linkedin.com\/pub\/jason-baldridge\/5\/629\/9b2","https:\/\/x.com\/http:\/\/twitter.com\/jasonbaldridge"],"url":"https:\/\/www.javacodegeeks.com\/author\/jason-baldridge"}]}},"_links":{"self":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/644","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/users\/67"}],"replies":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/comments?post=644"}],"version-history":[{"count":0,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/posts\/644\/revisions"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media\/227"}],"wp:attachment":[{"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/media?parent=644"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/categories?post=644"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/www.javacodegeeks.com\/wp-json\/wp\/v2\/tags?post=644"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}