通过删除Scala中不需要的值来过滤列表

时间:2018-10-23 10:05:06

标签: scala list

作为Scala的初学者,我偶然发现了一个似乎无法解决的问题。基本上,我从设法添加到列表的文件中获得坐标,然后将所有这些值排序到不同的列表中,如下所示:

List(List(61, 62, 63, 64, 65, 66, 67), List(21, 23, 25, 26, 27))

通过使用以下代码:

val lines = io.Source.fromFile("in.txt").getLines

val coordinates =
  lines
    .drop(0)
    .toList
    .sortWith(_<_)
    .mkString
    .replaceAll("\\s", "")
    .grouped(2)
    .toList

val conditions = 1 to 5000

val que = coordinates.map(_.toInt)

val thisIsIt = conditions.foldLeft(List():List[List[Int]])((acc, elem) =>
  que
    .filter(_.toString.startsWith(elem.toString))::acc)
    .filterNot(_.isEmpty)
    .filter(_.length > 3)
    .map(_.toList)

我要做的是在每个列表中找到遵循相同模式的坐标。例如,在列表

List(21, 23, 25, 26, 27) 

我想删除元素“ 26”,因为相邻值之间的差应为“ 2”。

23-21 = 2
25-23 = 2
26-25 = 1, 

但是,如果我们检查26之后的下一个元素与前一个元素25之间的差异,我们可以看到:

27-25 = 2

因此,如果删除26,则条件是每个之间的差异     相邻的值应为“ 2”为真,     给我们列表

List(21, 23, 25, 27)

另一个列表是:

List(61, 62, 63, 64, 65, 66, 67) 

应该只返回相同的列表,因为元素之间的差异是恒定的并且是“ 1”。

最后我应该得到清单

List(List(61, 62, 63, 64, 65, 66, 67), List(21, 23, 25, 27))

我将用列表给出另一个示例

List(31, 32, 33, 36, 37)

尽管前3个元素之间的差确实为“ 1”,并且关于后2个元素之间的差也可以说是相同的,但是无法通过常数从列表的开头遍历到列表的结尾值之间的差异。

坐标可以更改,每个列表中值的数量也可以更改。任何帮助将不胜感激,因为我已经死了。我尝试使用使用 head tail 的函数,遍历列表并应用条件,但似乎没有任何作用。

谢谢!

2 个答案:

答案 0 :(得分:0)

我仍然不知道我是否了解您要做什么。这是我认为的意思:找到给定列表的最长子列表,该子列表至少包含原始列表的三个元素,包括第一个和最后一个元素,以便每个元素之间的距离连续的元素是恒定的。

在这种情况下,这是一个简单的解决方案。 基本上,首先要找出所有可能的距离(通过从每个元素中减去列表的开头,并保留正值,但不大于列表的首尾之间距离的一半的值),然后尝试为每个距离构造结果子列表。

  def findIt(list: List[Int]) = {
    @tailrec def doIt(
      list: List[Int],
      candidates: List[Int],
      last: Int 
    ): Option[List[Int]] = candidates match {
       case Nil => None
       case dist :: rest => 
         val result = list.foldLeft[List[Int]](Nil) {
           case (Nil, x) => List(x)
           case (l@(head :: _), x) if x == head + dist => x :: l
           case (l, _) => l
         }
         if(result.head == last) Some(result.reverse) 
         else doIt(list, rest, last)
    }

    val candidates = list.foldLeft[List[Int]](Nil) { 
       case (Nil, x) => List(0)
       case (l, x) => (x - list.head) :: l
    }
    if(list.nonEmpty) doIt(
     list, 
     candidates.filter(x => x > 0 && x <= candidates.head/2).reverse, 
     list.head + candidates.head
    ) else None
 }

答案 1 :(得分:0)

听起来好像您只是想将每个List[Int]减少到等距的元素(如果有),并开始包含端点。

这是我的看法。

val input = List(List(61, 62, 63, 64, 65, 66, 67)
               , List(31, 32, 33, 36, 37)
               , List(21, 23, 25, 26, 27)
               , List(2, 12, 19, 22, 36))

val result = input.map{ lst =>
  val hd = lst.head
  val end = lst.last
  val distance = end - hd
  Stream.from(1).take(distance/2).flatMap{ step =>
    val rng = hd to end by step
    if (distance%step == 0 && rng.diff(lst).isEmpty)
      Some(rng.toList)
    else None
  }.headOption.getOrElse(Nil)
}
//result: List[List[Int]] = List(List(61, 62, 63, 64, 65, 66, 67)
//                             , List()
//                             , List(21, 23, 25, 27)
//                             , List(2, 19, 36))

注意:这假设每个List[Int]都被排序,或者至少.last被假定大于.head