我有这个:
List('a','a', 'a', 'b')
我想得到这个:
List(List('a','a', 'a'), List('b'))
这是我的代码:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x :: xs1 => val y = xs1.head
println("x is " + x)
println("y is " + y)
val (head,tail) = xs1 span ( x => x.equals(xs1.head))
println("head is " + head)
println("tail is " + tail)
(x :: head) :: pack(tail)
}
pack(List('a','a', 'a', 'b'))
返回以下内容:
x is a
y is a
head is List(a, a)
tail is List(b)
java.util.NoSuchElementException: head of empty list
问题:
谢谢
答案 0 :(得分:4)
直接回答您的问题:
case x :: xs1
语句将x
设置在xs
的头部,并将xs1
设置在其尾部。我想您可能希望您的span
语句为xs1 span(_ == x)
:从xs1
的尾部元素中选取与x
的第一个元素xs
相匹配的元素。因为您将span
应用于xs1
而不是xs
,所以错过了第一个元素。 (不过,您确实要在其后加上该值的开头。)但是,您的span
谓词看起来是xs1
的开头,而不是x
,从而导致错误-请参见答案( 2)。 (顺便说一句,您的x
函数中有两个不同的pack
变量,这使事情变得更加混乱,这就是为什么我将span
谓词参数匿名化了。)Nil
以获得空列表。当xs
仅包含一个元素时,即会出现错误,表示其尾部xs1
为空。查看空列表的head
会显示该错误。如果您想要连续显示相同元素的单独列表,那么span
将为您做到这一点:它将通过谓词的元素(与第一个字符相同的字符)放入其第一个返回列表中;但是一旦该谓词对于某个元素失败,该元素及其后的所有内容都会放入第二个列表中。因此,如果您期望如此,那是对的...
例如(在 Scala REPL 会话中):
$ scala
Welcome to Scala 2.12.6 (Java HotSpot(TM) 64-Bit Server VM, Java 1.8.0_171).
Type in expressions for evaluation. Or try :help.
scala> val xs = List('a', 'a', 'a', 'b')
xs: List[Char] = List(a, a, a, b)
scala> xs.span(_ == 'a')
res0: (List[Char], List[Char]) = (List(a, a, a),List(b))
我将像这样重写您的pack
函数,该函数更简单并避免了原始版本中的某些陷阱(即,删除xs
列表的开头,然后使用{{1 }}尾巴上的目标字符有误,然后尝试通过重新前缀原始头来重建列表):
span
但是,如果元素混合在一起,那么您可能不喜欢结果:
scala> def pack[T](xs: List[T]): List[List[T]] = xs match {
!
! // If xs is empty, return Nil.
! case Nil => Nil
!
! // Otherwise, the list is non-empty, so just process it.
! case _ => {
! val (head, tail) = xs.span(_ == xs.head)
!
! // Prefix head to packed tail.
! head :: pack(tail)
! }
! }
pack: [T](xs: List[T])List[List[T]]
scala> pack(xs)
res1: List[List[Char]] = List(List(a, a, a), List(b))
那是因为scala> val mixed = List('a', 'a', 'b', 'c', 'a', 'a', 'b', 'a')
mixed: List[Char] = List(a, a, b, c, a, a, b, a)
scala> pack(mixed)
res2: List[List[Char]] = List(List(a, a), List(b), List(c), List(a, a), List(b), List(a))
在谓词失败时停止查看元素。如果要将span
,'a'
和'b'
元素分成单独的列表,则需要'c'
而不是partition
:所有通过谓词的内容进入第一名单;一切都失败了您的span
函数将变为:
pack
答案 1 :(得分:1)
x :: xs
是用于匹配列表的开头(第一个元素)和结尾(其余)的模式。如果列表中包含1个元素,则tail将为Nil,但是您在该tail上调用.head
会导致错误。我认为做您想要的事情的一种方法是:
def pack[T](xs: List[T]): List[List[T]] = xs match {
case Nil => Nil
case x :: xs1 =>
val (prefix, rest) = xs1 span (_.equals(x))
(x :: prefix) :: pack(rest)
}
对于许多不同的元素,虽然这可能不是最好的方法。