从Scala中的匹配结果递归构建列表

时间:2013-09-18 16:35:12

标签: scala

我是Scala的新手,所以我只是在试验。以下代码在D:\ Downloads:

下递归打印出所有文件的名称
import java.io.File

object Run {
  def main (args: Array[String]){
    //read each file
    val f = new File("""D:\Downloads""");
    listFiles(f)
  }

  def listFiles(f: Any): Unit= f match{
    case f:File if f.isDirectory => f.listFiles().deep.foreach(listFiles(_))
    case f:File if f.isFile => println(f.getName)
    case _ => Unit
  }
}

这很有效。现在,我想listFiles建立一个字符串列表并返回它。这就是我所做的:

  def listFiles(f: Any): List[String] = f match{
    case f:File if f.isDirectory => f.listFiles().foreach(listFiles(_))
    case f:File if f.isFile => List(f.getName)
    case _ => Nil
  }

当f是目录时,foreach应递归调用listFiles并返回List。如何将所有这些数组连接在一起并返回它们?有没有更好的方法呢?

4 个答案:

答案 0 :(得分:5)

以下内容可能会有所改进,但它应该是一个可接受的起点:

def listFiles(f: File) = {
  def run(f: File, acc: List[File]): List[File] =
    if(f.isFile) f :: acc
    else         f.listFiles.foldLeft(acc) {(l, f) => run(f, l)}

  run(f, Nil)
}

答案 1 :(得分:5)

根据您的方法,使用flatMap

def listFiles(f: Any): List[String] = f match{
  case f:File if f.isDirectory => f.listFiles().toList.flatMap(listFiles(_))
  case f:File if f.isFile => List(f.getName)
  case _ => Nil
}

答案 2 :(得分:2)

你应该在文件列表中使用flatmap,但因为我更喜欢for-comprehensions看起来,这里:

 def listFiles(f: Any): List[String] = f match {
   case d: File if d.isDirectory => for {
      file <- d.listFiles.toList
      fileName <- listFiles(file)
      } yield fileName

   case f: File if f.isFile => List(f.getName)
   case _ => Nil
 }    

另一方面,您应该采用更强的类型安全性并将方法定义为:

 def listFiles(f:File): List[String]

这样它只能用File个参数调用,你可以在编译时捕获更多的错误。

答案 3 :(得分:1)

在尝试各种实现时,我最终对这个问题产生了兴趣。他们中的大多数人在我的计算机上花了一秒钟来列出一个相当嵌套的目录,共有大约4500个文件。

我使用Stream编写了一个实现,用于您可能不需要同时所有文件的实例。当你强行获取每个文件时,它似乎与List实现一样好。

import java.io.File

def listFiles(f : File): Stream[File] = {
  def streamFiles(fs : List[File]): Stream[File] = fs match {
    case x::xs => x match {
      case x if x.isDirectory => streamFiles(x.listFiles.toList) #::: streamFiles(xs)
      case x if x.isFile      => x #:: streamFiles(xs) 
    }
    case Nil    => Stream.empty
  }

  if (f.isDirectory)
    streamFiles(f.listFiles.toList)
  else
    f #:: Stream.empty
}

这将懒惰地生成您的文件列表。