2015-10-03 1 views
1

Если бы я был список, который выглядел так:Scala: группиЙ на основе булева применяются к следующему элементу

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

И я хотел закончить с

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

Как бы я сделать это?

Я пытался groupBy, но я не знаю, как применить логическое значение сначала получить ключ (т.е. string.contains("lists:")), а затем логический к следующему элементу, чтобы проверить, если он не содержит «списков: "и, следовательно, добавить его в качестве значения.

ответ

2

Предполагая структуру вами списка

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

Вы можете построить карту, как, что с 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) 

Если ключевые строки не всегда заканчиваются так же, как вы могли бы хотите использовать регулярное выражение для определения ключевых строк в вашем списке.

+0

работает отлично! – plambre

0

И снова предполагая, что структура всегда, как описано выше:

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 : _*) 

Если вы настаиваете на получение Seq, то вы можете сделать l.tail.toSeq вместо этого.

+0

К сожалению, я пропустил, что ключ «аннотирован» с двоеточием, и есть неизвестное количество элементов, поэтому мое решение не будет работать. – Markus

+0

Это определенно работало бы, если бы всегда было 3 отстающих предмета! – plambre

1

Использование multiSpan, как это определено в https://stackoverflow.com/a/21803339/3189923, учитывая

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

мы имеем, что

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

предоставляет список списков,

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

Таким образом, можно преобразовать в результате вложенных списков в желаемый Map, например, как fo л.,

xs.multiSpan(_.contains("lists:")).map(ys => ys.head -> ys.tail).toMap 
+0

Ничего себе, очень круто, спасибо – plambre

Смежные вопросы