【问题标题】:How can I find repeated items in a Scala List?如何在 Scala 列表中找到重复的项目?
【发布时间】:2013-09-27 22:23:27
【问题描述】:

我有一个包含一些重复数字的 Scala 列表。我想计算特定数字重复的次数。例如:

val list = List(1,2,3,3,4,2,8,4,3,3,5)
val repeats = list.takeWhile(_ == List(3,3)).size

而 val repeats 将等于 2

显然以上是伪代码,takeWhile 不会找到两个重复的3s,因为_ 代表一个整数。我尝试混合takeWhiletake(2) 但收效甚微。我还参考了How to find count of repeatable elements in scala list 的代码,但作者似乎正在寻求不同的东西。

感谢您的帮助。

【问题讨论】:

  • 查找“运行长度编码”,因为您想要的是相似的。还有sliding方法。
  • 不清楚。结果 2 可能意味着此数字重复两次 - 数字 3 重复出现 2 次 - 或 - 一次重复中的最大数量(这里也是 2)

标签: scala


【解决方案1】:

这将在这种情况下工作:

val repeats = list.sliding(2).count(_.forall(_ == 3))

sliding(2) 方法为您提供了一个元素列表和后继列表的迭代器,然后我们只计算这两个等于 3 的位置。

问题是它是否为 List(3, 3, 3) 创建了正确的结果?您希望重复 2 次还是仅重复 1 次。

【讨论】:

  • 回答你的问题,重复1次。重复多久没关系。另外,非常简洁的解决方案:)
【解决方案2】:
val repeats = list.sliding(2).toList.count(_==List(3,3))

更一般地说,以下代码返回元素元组并为所有元素重复值:

scala> list.distinct.map(x=>(x,list.sliding(2).toList.count(_.forall(_==x))))
res27: List[(Int, Int)] = List((1,0), (2,0), (3,2), (4,0), (8,0), (5,0))

这意味着元素“3”在 2 个位置连续重复 2 次,其他所有重复 0 次。

如果我们想要元素连续重复3次,我们只需要修改代码如下:

list.distinct.map(x=>(x,list.sliding(3).toList.count(_.forall(_==x))))

在 SCALA REPL 中:

scala> val list = List(1,2,3,3,3,4,2,8,4,3,3,3,5)
list: List[Int] = List(1, 2, 3, 3, 3, 4, 2, 8, 4, 3, 3, 3, 5)

scala> list.distinct.map(x=>(x,list.sliding(3).toList.count(_==List(x,x,x))))
res29: List[(Int, Int)] = List((1,0), (2,0), (3,2), (4,0), (8,0), (5,0))

甚至可以通过定义一个函数来改变滑动值:

def repeatsByTimes(list:List[Int],n:Int) =
list.distinct.map(x=>(x,list.sliding(n).toList.count(_.forall(_==x))))

现在在 REPL:

scala> val list = List(1,2,3,3,4,2,8,4,3,3,5)
list: List[Int] = List(1, 2, 3, 3, 4, 2, 8, 4, 3, 3, 5)

scala> repeatsByTimes(list,2)
res33: List[(Int, Int)] = List((1,0), (2,0), (3,2), (4,0), (8,0), (5,0))

scala> val list = List(1,2,3,3,3,4,2,8,4,3,3,3,2,4,3,3,3,5)
list: List[Int] = List(1, 2, 3, 3, 3, 4, 2, 8, 4, 3, 3, 3, 2, 4, 3, 3, 3, 5)

scala> repeatsByTimes(list,3)
res34: List[(Int, Int)] = List((1,0), (2,0), (3,3), (4,0), (8,0), (5,0))

scala>

我们可以更进一步,比如给定一个整数列表并给定一个最大数 对于任何元素可以在列表中出现的连续重复,我们可能需要一个 3 元组列表来表示(元素、该元素的重复次数、该重复发生的位置)。这是比上述更详尽的信息。可以通过编写这样的函数来实现:

 def repeats(list:List[Int],maxRep:Int) =
 { var v:List[(Int,Int,Int)] = List();
 for(i<- 1 to maxRep)
 v = v ++ list.distinct.map(x=> 
 (x,i,list.sliding(i).toList.count(_.forall(_==x))))
 v.sortBy(_._1) }

在 SCALA REPL 中:

scala> val list = List(1,2,3,3,3,4,2,8,4,3,3,3,2,4,3,3,3,5)
list: List[Int] = List(1, 2, 3, 3, 3, 4, 2, 8, 4, 3, 3, 3, 2, 4, 3, 3, 3, 5)


scala> repeats(list,3)
res38: List[(Int, Int, Int)] = List((1,1,1), (1,2,0), (1,3,0), (2,1,3), 
 (2,2,0), (2,3,0), (3,1,9), (3,2,6), (3,3,3), (4,1,3), (4,2,0), (4,3,0), 
 (5,1,1), (5,2,0), (5,3,0), (8,1,1), (8,2,0), (8,3,0))

scala>

这些结果可以理解为:

   1 times the element '1' occurred at 1 places.
   2 times the element '1' occurred at 0 places.
   ............................................
   ............................................
   .............................................
   2 times the element '3' occurred at 6 places..
   .............................................
   3 times the element '3' occurred at 3 places...
   ............................................and so on.

【讨论】:

  • 为什么要添加toList?它似乎没有任何目的。此外,这与 4 年前接受的答案几乎相同。在为旧问题添加更多答案时,最好指出您的答案提供的与其他答案不同的地方。
  • 旧的答案是好的..但这一次概括并重复了所有元素的值..我觉得至少有一点改进。
【解决方案3】:

感谢Luigi Plinge,我能够使用行程编码中的方法将重复的列表中的项目组合在一起。我在这里使用了此页面中的一些 sn-ps:http://aperiodic.net/phil/scala/s-99/

var n = 0
runLengthEncode(totalFrequencies).foreach{ o => 
  if(o._1 > 1 && o._2==subjectNumber) n+=1
}
n

方法runLengthEncode如下:

  private def pack[A](ls: List[A]): List[List[A]] = {
    if (ls.isEmpty) List(List())
    else {
      val (packed, next) = ls span { _ == ls.head }
      if (next == Nil) List(packed)
      else packed :: pack(next)
    }
  }

  private def runLengthEncode[A](ls: List[A]): List[(Int, A)] =
    pack(ls) map { e => (e.length, e.head) }

我并不完全满意我需要使用可变 var n 来计算出现次数,但它确实成功了。这将计算一个数字重复自身的次数,无论它重复多少次。

【讨论】:

  • 您可以使用count 方法,或更一般的foldLeft 来避免使用var
【解决方案4】:

如果您知道您的列表不是很长,您可以使用 字符串

val list = List(1,2,3,3,4,2,8,4,3,3,5)
val matchList = List(3,3)
(matchList.mkString(",")).r.findAllMatchIn(list.mkString(",")).length

【讨论】:

    【解决方案5】:

    从你的伪代码我得到了这个工作:

    val pairs = list.sliding(2).toList  //create pairs of consecutive elements
    val result = pairs.groupBy(x => x).map{ case(x,y) => (x,y.size);   //group pairs and retain the size, which is the number of occurrences.
    

    result 将是 Map[List[Int], Int],因此您可以像这样计算数字:

     result(List(3,3))    // will return 2 
    

    我不明白您是否还想检查多个尺寸的列表,那么您需要将参数更改为 sliding 为所需的尺寸。

    【讨论】:

      【解决方案6】:
      def pack[A](ls: List[A]): List[List[A]] = {
        if (ls.isEmpty) List(List())
        else {
          val (packed, next) = ls span { _ == ls.head }
          if (next == Nil) List(packed)
          else packed :: pack(next)
        }
      }
      
      def encode[A](ls: List[A]): List[(Int, A)] = pack(ls) map { e => (e.length, e.head) }
      
      val numberOfNs = list.distinct.map{ n =>
        (n -> list.count(_ == n))
       }.toMap
      
      val runLengthPerN = runLengthEncode(list).map{ t => t._2 -> t._1}.toMap
      
      val nRepeatedMostInSuccession = runLengthPerN.toList.sortWith(_._2 <= _._2).head._1
      

      其中 runLength 定义如下,来自 scala's 99 problems problem 9scala's 99 problems problem 10

      由于numberOfNsrunLengthPerNMaps,你可以用numberOfNs(number)得到列表中任意数字的人口数,用runLengthPerN(number)连续得到最长重复的长度。要获得runLength,只需使用runLength(list).map{ t =&gt; t._2 -&gt; t._1 } 进行上述计算即可。

      【讨论】:

      • 我不认为这是他想要的。
      • 是的,我也不确定。也许他想要一个连续重复的列表?我将添加该示例以及找到最长重复的示例。
      • 刚刚想通了,我现在正在提交答案:)
      • 我认为他想要一个函数 (List,int)=>int 来找到作为参数传递的 int 的最长重复。在他的示例中,对于 3,希望看到 2 作为结果。
      • 感谢DeLongey,当然还有Phil Gold
      猜你喜欢
      • 2018-11-07
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2014-09-03
      • 1970-01-01
      • 2013-09-18
      • 1970-01-01
      相关资源
      最近更新 更多