scala跨度方法的行为不符合预期
我有这个:scala跨度方法的行为不符合预期,scala,list,Scala,List,我有这个: 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)
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
问题:
谢谢
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)
}
对于许多不同的元素,这可能不是最好的方法。要直接回答您的问题:
case x::xs1
语句将x
设置为xs
的头部,将xs1
设置为其尾部。我想您可能希望您的span
语句是xs1 span(==x)
:从xs1
中获取与xs
的第一个元素x
相匹配的元素。由于您将span
应用于xs1
,而不是xs
,因此缺少了第一个元素。(不过,您会在头后面加上该值作为前缀。)但是,span
谓词会查看xs1
的头,而不是x
,从而导致错误-请参见答案(2)。(顺便说一句,您的pack
函数中有两个不同的x
变量,这使问题变得更加混乱,这就是我将span
谓词参数匿名化的原因。)Nil
。当xs
只有一个元素时会出现错误,这意味着它的尾部xs1
为空。查看空列表的标题
,会出现该错误span
将为您做到这一点:它将传递谓词的元素(与第一个字符相同的字符)放入其第一个返回的列表中;但是,一旦某个元素的谓词失败,该元素和随后的所有内容都将被放入第二个列表中。所以如果你期待的话,你是对的
例如(在Scala REPL会话中):
$scala
欢迎使用Scala 2.12.6(Java热点(TM)64位服务器虚拟机,Java 1.8.0_171)。
键入要计算的表达式。或者尝试:帮助。
scala>val xs=List('a','a','a','b')
xs:List[Char]=列表(a,a,a,b)
scala>xs.span(=='a')
res0:(列表[Char],列表[Char])=(列表(a,a,a),列表(b))
我会像这样重写你的pack
函数,它更简单,并且避免了原始版本中的一些陷阱(即,删除xs
列表的头部,然后在尾部使用span
和错误的目标字符,然后尝试通过在原始头部添加前缀来重建列表):
scala>def-pack[T](xs:List[T]):List[List[T]=xs-match{
!
!//如果xs为空,则返回Nil。
!case Nil=>Nil
!
!//否则,列表为非空,请处理它。
!case=>{
!val(head,tail)=xs.span(==xs.head)
!
!//从头部到尾部的前缀。
!头::包(尾)
! }
! }
包装:[T](xs:List[T])列表[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')
混合:列表[字符]=列表(a,a,b,c,a,a,b,a)
scala>包装(混合)
res2:List[List[Char]=List(List(a,a),List(b),List(c),List(a,a),List(b),List(a))
这是因为当谓词失败时,span
停止查看元素。如果您想将'a'
,'b'
和'c'
元素分离到单独的列表中,那么您需要分区
,而不是span
:传递谓词的所有内容都进入第一个列表;所有失败的事情都会进入第二阶段。您的pack
功能将变为:
scala>def pack2[T](xs:List[T]):List[List[T]=xs匹配{
!
!//如果xs为空,则返回Nil。
!case Nil=>Nil
!
!//否则,列表为非空,请处理它。
!case=>{
!val(head,tail)=xs.partition(==xs.head)
!
!//从头部到尾部的前缀。
!head::pack2(tail)
! }
! }
pack2[T](xs:List[T])List[List[T]]
scala>pack2(xs)
res3:List[List[Char]=List(List(a,a,a),List(b))
scala>pack2(混合)
res4:List[List[Char]=List(List(List(a,a,a,a,a),List(b,b),List(c))