我想创建一个scala方法,该方法计算值相同的连续字符的数量。所以我有这个清单:
List('a','a','b')
,我想返回类似List(('a',2),'b',1)之类的东西-因为两个字符之间的值相同。我对此一无所获,但收效甚微:
def recursivelyCompressList(list: List[(Char, Int)], newString: List[(Char, Int)]): List[(Char, Int)] = {
list match {
case Nil => newString
case s :: tail => {
if (tail.nonEmpty && s._1 == tail.head._1) {
recursivelyCompressList(tail, newString :+ (s._1, s._2 + 1))
} else {
recursivelyCompressList(tail, newString :+ s)
}
}
case _ => newString
}
}
感谢任何指导。
答案 0 :(得分:1)
还可以使用span
代替dropWhile和takeWhile以避免双重扫描
def comp(xs:List[Char]):List[(Char,Int)] =
if(xs.isEmpty) Nil
else {
val h = xs.head
val (m,r) = xs.span(_ == h)
(h, m.length) :: comp(r)
}
答案 1 :(得分:0)
这应该有效。
我希望代码会自我解释,但是如果您有任何疑问,请不要怀疑。
def compressList[T](list: List[T]): List[(T, Int)] = {
@annotation.tailrec
def loop(remaining: List[T], currentValue: T, currentCount: Int, acc: List[(T, Int)]): List[(T, Int)] =
remaining match {
case Nil =>
((currentValue -> currentCount) :: acc).reverse
case t :: tail =>
if (t == currentValue)
loop(
remaining = tail,
currentValue,
currentCount + 1,
acc
)
else
loop(
remaining = tail,
currentValue = t,
currentCount = 1,
(currentValue -> currentCount) :: acc
)
}
list match {
case Nil =>
Nil
case t :: tail =>
loop(
remaining = tail,
currentValue = t,
currentCount = 1,
acc = List.empty
)
}
}
您可以这样使用:
compressList(List.empty[Char])
// res: List[(Char, Int)] = List()
compressList(List('a', 'b'))
// res: List[(Char, Int)] = List(('a', 1), ('b', 1))
compressList(List('a', 'a', 'b'))
// res: List[(Char, Int)] = List(('a', 2), ('b', 1))
compressList(List('a', 'a', 'b', 'b', 'b', 'a', 'c'))
// res: List[(Char, Int)] = List(('a', 2), ('b', 3), ('a', 1), ('c', 1))
答案 2 :(得分:0)
使用takeWhile
和dropWhile
连续计数
def count(xs: List[Char]): List[(Char, Int)] =
if (xs.isEmpty) Nil else
(xs.head, xs.takeWhile(_ == xs.head).length) :: count(xs.dropWhile(_ == xs.head))
scala> def count(xs: List[Char]): List[(Char, Int)] =
| if (xs.isEmpty) Nil else
| (xs.head, xs.takeWhile(_ == xs.head).length) :: count(xs.dropWhile(_ == xs.head))
count: (xs: List[Char])List[(Char, Int)]
scala> count(List('a', 'a', 'b', 'c', 'c', 'c'))
res0: List[(Char, Int)] = List((a,2), (b,1), (c,3))
scala> count(List('a', 'a', 'b', 'a', 'c', 'c', 'c'))
res1: List[(Char, Int)] = List((a,2), (b,1), (a,1), (c,3))
答案 3 :(得分:0)
如果存在多个相同字符的重复序列,则尚未指定所需的行为。假设您只想要最长的重复序列,那么以下代码将是一个很好的起点:
def rec(list : List[Char]) : Map[Char, Int] = {
@scala.annotation.tailrec
def helper(prev: Char, li : List[Char], len : Int, result : Map[Char, Int]) : Map[Char,Int] = {
if(li.isEmpty) {
if(!result.contains(prev)) result + (prev -> len)
else if(result(prev) < len) result + (prev -> len)
else result
}
else {
val cur = li.head
if(cur != prev) {
if(result.contains(prev)) {
if(result(prev) < len)
helper(li.head, li.tail, 1, result + (prev -> len))
else
helper(li.head, li.tail, 1, result)
} else {
helper(li.head, li.tail, 1, result + (prev -> len))
}
} else {
helper(li.head, li.tail, len + 1, result)
}
}
}
helper('\0', list, 0, Map.empty[Char, Int]) - '\0'
}
运行
rec(List('c', 'a', 'a', 'a', 'c', 'd' ,'c', 'c' , 'a', 'a', 'd', 'd', 'd', 'd','c','c','a', 'c','c','c'))
输出:
res0: Map[Char,Int] = Map(c -> 3, a -> 3, d -> 4)
这个想法只是看列表中的当前字符和前一个字符。当字符更改时,序列计数将停止,并将当前长度与映射中存储的长度进行比较。当您考虑它时,这很简单。
我认为这可以写得更加优雅。但这可能是一个很好的起点。