1

If I had a List that looked like this:

List("abdera.apache.org lists:", "commits", "dev", "user",
"accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

And I wanted to end with a

Map("abdera.apache.org lists:" -> Seq("commits", "dev", "user"), 
"accumulo.apache.org lists:" -> Seq("commits", "dev", "notifications", "user"))

How would I do that?

I've been trying groupBy, but I'm not sure how to apply a boolean to first get the key (i.e. string.contains("lists:")) and then a boolean to the next element to test if it doesn't contain "lists:" and therefore add it as a value.

elm
  • 20,117
  • 14
  • 67
  • 113
plamb
  • 5,636
  • 1
  • 18
  • 31

3 Answers3

2

Assuming the structure of you list is

List(key, item, item, item, 
     key, item ..., item, 
     key, item, ...)

You can build a map like that with a foldLeft:

val list = List("abdera.apache.org lists:", "commits", "dev", "user",
  "accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

val map: Map[String, List[String]] =
  list.foldLeft(List.empty[(String, List[String])]) {

    case (acc, curr) if curr.endsWith("lists:") =>
      // identified a list key
      curr -> List.empty[String] :: acc

    case (((headListKey, headList)) :: tail, curr) =>
      // append current string to list of strings of head, until next list key is found
      (headListKey, curr :: headList) :: tail

  }.toMap.mapValues(_.reverse)

If the key strings do not always end the same way, you might want to use a regular expression to identify the key strings in your list.

Sascha Kolberg
  • 7,092
  • 1
  • 31
  • 37
1

Using multiSpan as defined in https://stackoverflow.com/a/21803339/3189923 , given

val xs = List("abdera.apache.org lists:", "commits", "dev", "user",
              "accumulo.apache.org lists:", "commits", "dev",
                                            "notifications", "user")

we have that

xs.multiSpan(_.contains("lists:"))

delivers a list of lists,

List(List(abdera.apache.org lists:, commits, dev, user),
     List(accumulo.apache.org lists:, commits, dev, notifications, user))

We can thus transform the resulting nested lists into the desired Map, for instance as follows,

xs.multiSpan(_.contains("lists:")).map( ys => ys.head -> ys.tail ).toMap
Community
  • 1
  • 1
elm
  • 20,117
  • 14
  • 67
  • 113
0

And again assuming that structure is always as outlined above:

val list = List("abdera.apache.org lists:", "commits", "dev", "user",
  "accumulo.apache.org lists:", "commits", "dev", "notifications", "user")

Map(list.grouped(4).map(l => (l.head -> l.tail)).toList : _*)

If you insist on getting a Seq then you can do l.tail.toSeq instead.

Markus
  • 1,293
  • 9
  • 10
  • Sorry, I missed that the key is "annotated" with a colon and there are an unknown number of items, so my solution will not work. – Markus Oct 04 '15 at 09:15
  • This would definitely work if there was always 3 trailing items though! – plamb Oct 05 '15 at 16:40