【问题标题】:How to simplify Option processing如何简化期权处理
【发布时间】:2020-09-01 16:42:16
【问题描述】:

我有一个包含数据的源列表,我想将其排序为 3 个包含已清理数据、更新数据并记录的列表。源中的所有元素都必须在记录列表中。所有具有非空值的元素都必须在清理列表中,如果更新了标志,该元素也必须出现在更新的文件夹中。

根据例子:

  • 更新 = 2,4 el
  • 记录 = 1,2,3,4 el
  • 清洁 = 3, 4 el

你能帮我简化写好的代码吗:

case class Source(value: Option[String], date: String, isUpdate: Boolean)

case class Cleaned(value: String, date: String)
case class Logged(value: String, date: String)
case class Updated(value: String, date: String)

val sources: List[Source] = List(
    Source(Option.empty[String], "2020-01-09", false), // 1
    Source(Option.empty[String], "2020-01-09", true), // 2
    Source(Option("Some Data"), "2020-01-09", false), // 3
    Source(Option("Some Data 2"), "2020-01-09", true) // 4
)


val target = sources.foldLeft(List.empty[Updated], List.empty[Logged], List.empty[Cleaned]){
    case ((updated, logged, cleaned), el) if el.isUpdate =>
        (updated  :+ Updated(el.value.getOrElse(""), el.date),
            logged :+ Logged(el.value.getOrElse(""), el.date),
            el.value.fold(cleaned)(d => cleaned :+ Cleaned(d, el.date))
        )

    case ((updated, logged, cleaned), el) =>
        (updated,
            logged :+ Logged(el.value.getOrElse(""), el.date),
            el.value.fold(cleaned)(d => cleaned :+ Cleaned(d, el.date))
        )
}

【问题讨论】:

  • 你确定updated 应该包含第二个元素吗?我阅读要求的方式是该值应该存在并且标志为true

标签: scala option fold


【解决方案1】:

您可以构建自己的折叠运算符并使用 foldRight 方法将其传递:

type Targets = (List[Updated], List[Logged], List[Cleaned])
val target = sources.foldRight(List.empty[Updated], List.empty[Logged], List.empty[Cleaned])(process)

def process(el: Source, acc: Targets): Targets = acc match {
  case (updated, logged, cleaned) => el match {
    case Source(None, date, false) =>
      (updated, Logged("", date) :: logged, cleaned)

    case Source(Some(value), date, false) =>
      (updated, Logged(value, date) :: logged, Cleaned(value, date) :: cleaned)

    case Source(None, date, true) =>
      (Updated("", date) :: updated, Logged("", date) :: logged, cleaned)

    case Source(Some(value), date, true) =>
      (Updated(value, date) :: updated, Logged(value, date) :: logged, Cleaned(value, date) :: cleaned)
  }
}

【讨论】:

    【解决方案2】:

    我个人认为这是最好使用递归解决的问题。
    代码更大,但恕我直言,更容易理解和更改。

    type Result = (List[Logged], List[Cleaned], List[Updated])
    
    def process(data: List[Source]): Result = {
      @annotation.tailrec
      def loop(remaining: List[Source], logged: List[Logged], cleaned: List[Cleaned], updated: List[Updated]): Result =
        remaining match {
          case Source(Some(value), date, true) :: xs =>
            loop(
              remaining = xs,
              Logged(value = value, date) :: logged,
              Cleaned(value, date) :: cleaned,
              Updated(value, date) :: updated
            )
          
          case Source(Some(value), date, false) :: xs =>
            loop(
              remaining = xs,
              Logged(value = value, date) :: logged,
              Cleaned(value, date) :: cleaned,
              updated
            )
          
          case Source(None, date, _) :: xs =>
            loop(
              remaining = xs,
              Logged(value = "", date) :: logged,
              cleaned,
              updated
            )
          
          case Nil=>
            // If the order is not important, remove all the reverse.
            (
              logged.reverse,
              cleaned.reverse,
              updated.reverse
            )
        }
      
      loop(remaining = data, logged = List.empty, cleaned = List.empty, updated = List.empty)
    }
    

    可以看到运行here的代码。

    【讨论】:

      【解决方案3】:

      除非存在大量性能问题,否则只需处理列表 3 次:

      val target =
        (
          sources.flatMap { el =>
            if (el.isUpdate) Some(Updated(el.value.getOrElse(""), el.date)) else None
          },
          sources.map(el => Logged(el.value.getOrElse(""), el.date)),
          sources.flatMap { el =>
            el.value.map(d => Cleaned(d, el.date))
          }
        )
      

      【讨论】:

        猜你喜欢
        • 2011-07-16
        • 2010-10-18
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-04-23
        相关资源
        最近更新 更多