【问题标题】:Filter scala collection of objects with custom logic使用自定义逻辑过滤对象的 scala 集合
【发布时间】:2021-11-26 23:33:59
【问题描述】:

我需要过滤一组对象(已经按属性 A 排序)删除属性 B 乱序的项目(下面用粗体标记): (为简单起见,一组元组)

案例一:

  • 输入Seq((10, 10), (20, 20), (30, 36), (40, 30), (50, 40), (60, 50))
  • 预期输出:Seq((10, 10), (20, 20), (30, 36), (50, 40), (60, 50))
  • 实际输出:Seq((10,10), (20,20), (40,30), (50,40))

案例2:

  • 输入:Seq((10, 10), (20, 20), (30, 36), (40, 40), (50, 30), (60, 50))
  • 预期输出:Seq((10, 10), (20, 20), (30, 36), (40, 40), (60, 50))
  • 实际输出:Seq((10,10), (20,20), (30,36), (50,30))

我将不胜感激。

这是我目前所拥有的:

@RunWith(classOf[SpringRunner])
class OutOfOrderTest extends AnyWordSpec with Matchers with Debuggable {

  "OutOfOrderTest" should {

    def ooo(a: Seq[(Int, Int)]): Option[(Int, Int)] = {
      val x = a.head
      val y = a.tail.head
      if (x._2 <= y._2) Some(x) else None
    }

    "filter out of order simple" in {
      val bad = Seq((10, 10), (20, 20), (30, 36), (40, 30), (50, 40), (60, 50))

      val filtered = bad.sliding(2).collect { a =>
        ooo(a)
      }.filter(_.isDefined).map(_.get).toSeq
      filtered shouldEqual Seq((10, 10), (20, 20), (30, 36), (50, 40), (60, 50))
    }

    "filter out of order complex" in {
      val bad2 = Seq((10, 10), (20, 20), (30, 36), (40, 40), (50, 30), (60, 50))

      val filtered2 = bad2.sliding(2).collect { a =>
        ooo(a)
      }.filter(_.isDefined).map(_.get).toSeq
      filtered2 shouldEqual Seq((10, 10), (20, 20), (30, 36), (40, 40), (60, 50))
    }
  }
}

更新 1

我使用序列来提高性能(可能最好使用数组,但我可以稍后处理)

为简单起见,我在这里使用了元组,但它们实际上是案例类 (Target) 的实例,其中 2 个字段由元组数据表示。

这也是一个更大的 Spring-boot 应用程序中的一个过滤器,我必须用它制作一个组件。

虽然“组件化”(是的,我们在办公室里提出了这个词)过滤器没有问题,但来自@Luis 的递归函数将难以抽象如下:

我想将这三种方法作为组件进行测试 因此,如果可以的话,我会将 3 个答案标记为有效。

case class Target(rt: Double, ri: Double)

trait OutOfOrderRemover {
  def filter(targets: Seq[Target])
}

@Component
class RecurtsiveOOO extends OutOfOrderRemover {
  override def filter(targets: Seq[Target]): Seq[Target] = { }
}

【问题讨论】:

  • 感谢所有 jwvh、Guru 和 Luis 的快速回答,每个人都有我喜欢的东西,jwvh 非常简洁,Guru 使用折叠,Luis 使用递归。

标签: spring-boot scala filtering scala-collections


【解决方案1】:

这是我的 2 美分。

这将为已发布的两个 input 示例返回所需的结果。

input.head +: input.sliding(2).collect{
      case Seq((_,b1),(a2,b2)) if b1 <= b2 => (a2,b2)
    }.toSeq

警告:如果input 为空,将抛出。

【讨论】:

    【解决方案2】:

    恕我直言,这是尾递归的完美用例。

    def removeUnsortedElements[A, B](data: List[A])(orderBy: A => B)(implicit ev: Ordering[B]): List[A] = {
      import Ordering.Implicits._
    
      @annotation.tailrec
      def loop(remaining: List[A], previous: B, acc: List[A]): List[A] =
        remaining match {
          case a :: tail =>
            val next = orderBy(a)
            val newAcc =
              if (next >= previous) a :: acc
              else acc
            
            loop(
              remaining = tail,
              previous = next,
              acc = newAcc
            )
          
          case Nil =>
            acc.reverse
        }
      
      data match {
        case first :: tail =>
          loop(
            remaining = tail,
            previous = orderBy(first),
            acc = first :: Nil
          )
        
        case Nil =>
          Nil
      }
    }
    

    可以这样使用:

    val input1 = List((10, 10), (20, 20), (30, 36), (40, 30), (50, 40), (60, 50))
    val output1 = removeUnsortedElements(input1)(_._2)
    // output1: List[Int] = List((10,10), (20,20), (30,36), (50,40), (60,50))
    
    val input2 = List((10, 10), (20, 20), (30, 36), (40, 40), (50, 30), (60, 50))
    val output2 = removeUnsortedElements(input2)(_._2)
    // output2: List[Int] = List((10,10), (20,20), (30,36), (40,40), (60,50))
    

    可以看到运行here的代码

    【讨论】:

      【解决方案3】:

      您可以将foldLeft与空集合累加器一起使用,将当前值与累加器头部1进行比较,如果满足条件则追加当前值,然后反转结果:

      val bad = ...
      val filtered = bad.foldLeft(List.empty[(Int, Int)])((acc, t) => acc match {
          case head :: _ if head._2 > t._2 => acc
          case _ => t :: acc
        })
          .reverse
      

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2021-05-17
        • 1970-01-01
        • 2017-03-09
        • 2016-11-18
        • 1970-01-01
        • 1970-01-01
        • 2013-07-02
        • 1970-01-01
        相关资源
        最近更新 更多