如何简化期权处理

问题描述

我有一个包含数据的源列表,我想将其分类为3个包含清除数据,更新数据并记录的列表。来自源的所有元素都必须在日志列表中。所有具有非空值的元素都必须在清除列表中,并且如果更新了标志,则该元素也必须出现在更新的文件夹中。

根据示例:

  • updated = 2,4 el
  • 已记录= 1,2,3,4 el
  • cleaned = 3,4 el

您能帮我简化书面代码吗?

When I choose a movie by "<movie_name>" and play

Examples: {'datafile' : 'src/main/resources/data/testData.xls','sheetName' : 'movie_demo'}

解决方法

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

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),false) :: xs =>
        loop(
          remaining = xs,updated
        )
      
      case Source(None,_) :: xs =>
        loop(
          remaining = xs,Logged(value = "",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的代码。

,

您可以构造自己的折叠运算符,并使用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,false) =>
      (updated,Logged("",cleaned)

    case Source(Some(value),Logged(value,date) :: cleaned)

    case Source(None,true) =>
      (Updated("",date) :: updated,true) =>
      (Updated(value,date) :: cleaned)
  }
}
,

除非存在严重的性能问题,否则只需处理列表三遍:

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))
    }
  )