开始Scala 2.13,List现在随unfold构建器一起提供,可以与List::span:
// val list = List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
List.unfold(list) {
case Nil => None
case rest => Some(rest.span(_ == rest.head))
}
// List[List[Symbol]] = List(List('a, 'a, 'a, 'a), List('b), List('c, 'c), List('a, 'a), List('d), List('e, 'e, 'e, 'e))
或者,与Scala 2.13's Option#unlessbuilder 结合使用:
List.unfold(list) {
rest => Option.unless(rest.isEmpty)(rest.span(_ == rest.head))
}
细节:
- Unfold 使用一个内部状态,在我们的例子中用
listto split初始化List('a, 'a, 'a, 'a, 'b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)
- 在每次迭代中,我们
span为了找到包含相同符号的前缀的内部状态:l.span(_ == l.head)这是在第一次迭代期间l.span(_ == 'a)并给出(List('a, 'a, 'a, 'a),List('b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e))
- 正如
unfold预期的那样,元组的每个迭代的Option第一部分是要添加到正在构建的列表中的新元素(此处List('a, 'a, 'a, 'a)),其第二部分是内部状态的新值(此处List('b, 'c, 'c, 'a, 'a, 'd, 'e, 'e, 'e, 'e)),该跨度完全符合该要求。
- 我们不断迭代相同的步骤,直到内部列表为空,在这种情况下,我们
unfold通过返回来告诉 ing 我们已经完成None。