【问题标题】:Filtering a list by removing unwanted values in Scala通过在 Scala 中删除不需要的值来过滤列表
【发布时间】:2018-10-23 10:05:05
【问题描述】:

作为 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个元素之间的差异也可以这样说,但是没有办法用一个常数从列表的开头遍历到它的结尾值之间的差异。

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

提前致谢!

【问题讨论】:

  • 您能否在列表中列出您希望拥有的模式
  • 你的意思是“没有办法从列表的开头遍历到它的结尾,值之间的差异是恒定的。”?当然有!只需删除最后两个元素。或前三个。
  • @ChaitanyaWaikar 就是这样,模式实际上取决于列表中的值。主要目标是找到一种模式,您可以使用该模式从头到尾遍历列表,但模式必须是静态的。
  • @Dima ,可以,是的,但是我得到的任务要求我检查是否可以使用某种模式遍历整个列表,如果不可能,那么它应该只返回一个空列表。
  • @gibepesos 您的第一个示例从列表中删除了一个元素...如果这就是您所说的“使用某种模式遍历”,那么这与我建议您在最后一种情况下做的完全相同- 只需删除最后两个元素,然后剩下的就是_ + 1

标签: scala list


【解决方案1】:

听起来您可能只想将每个 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

【讨论】:

  • 完美,这正是我一直在寻找的,是的,您假设每个List[Int] 都被订购是正确的!
【解决方案2】:

我仍然不知道我是否理解你想要做什么。这是我认为你可能的意思:找到给定列表的最长可能子列表,至少包含原始列表的三个元素,包括第一个和最后一个元素,这样每个列表之间的距离连续的元素是常数。

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

  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
 }

【讨论】:

  • 谢谢你,这行得通,最后你明白了我在找什么!非常感谢!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-29
  • 1970-01-01
  • 2017-06-14
  • 2018-11-19
  • 1970-01-01
相关资源
最近更新 更多