首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >管道Array.reduce FileInfo[][]到FileInfo[]

管道Array.reduce FileInfo[][]到FileInfo[]
EN

Stack Overflow用户
提问于 2016-10-08 00:33:57
回答 3查看 88关注 0票数 3
代码语言:javascript
复制
exception NoDirectory of string

let dir = DirectoryInfo "c:\\"

let dirExists (dir: DirectoryInfo): bool = dir.Exists


let rec getFiles (dir: DirectoryInfo) : FileInfo[] = 
    let subs = 
            match dirExists dir with
                | true -> dir.GetDirectories ""
                | false -> raise (NoDirectory("error"))
    subs
      |> Array.map (fun (dir: DirectoryInfo) -> getFiles dir)
      |> Array.reduce (fun acc elem -> acc.append elem) List.empty 

因此,我正在尝试的最后一行将FileInfo[][]还原为FileInfo[],或者更准确地说,将FileInfo[][]还原为List<FileInfo>

我认为,因为管道只在一元函数上工作,所以这意味着函数运行Array.reduce,但我被困在那里,类似于:

代码语言:javascript
复制
let unaryReduce (fileInfoArray: FileInfo[]) = Array.reduce (fun acc elem -> acc.append elem) List.empty

我说的对吗?接近..。很远..。

编辑

因此,经过一些修改后,我得到了这个:

代码语言:javascript
复制
let dir = DirectoryInfo "c:\\"

let dirExists (dir: DirectoryInfo): bool = dir.Exists

let getFiles (dir: DirectoryInfo) : FileInfo[] = dir.GetFiles ""

let rec recursiveGetFiles (dir: DirectoryInfo) : FileInfo[] = 
    let subs = 
            match dirExists dir with
                | true -> dir.GetDirectories ""
                | false -> raise (NoDirectory("error"))
    subs
      |> Array.collect (fun (dir: DirectoryInfo) -> recursiveGetFiles dir)
      |> Array.concat<FileInfo[]> getFiles <| dir

我昨天才开始看F#,我想试试用管道。我得到的错误在最后一行:

此表达式应具有类型。 FileInfo [] -> 'a -> FileInfo [] 但这里有类型 FileInfo

这告诉我,collect没有被正确的使用来扁平数组.

EN

回答 3

Stack Overflow用户

回答已采纳

发布于 2016-10-08 12:23:27

如果您想要使用管道,这样的东西应该可以工作:

代码语言:javascript
复制
exception NoDirectory of string

// DirectoryInfo -> bool
let dirExists (dir: DirectoryInfo) = dir.Exists

// DirectoryInfo -> FileInfo []
let getFiles (dir: DirectoryInfo) = dir.GetFiles "."

// DirectoryInfo -> FileInfo []
let rec recursiveGetFiles dir = 
    match dirExists dir with
    | true -> dir.GetDirectories "."
    | false -> raise (NoDirectory "error")
    |> Array.collect recursiveGetFiles
    |> Array.append (getFiles dir)

我不建议抛出像这里所示的异常,但是我保留了这个部分,以便使它尽可能接近OP。但是,一旦您熟悉了F#和函数式编程的基础知识,您就应该了解使用任一单块处理函数错误的方法。这里是一个很好的起点:http://fsharpforfunandprofit.com/rop

票数 2
EN

Stack Overflow用户

发布于 2016-10-08 12:54:08

从编辑中得到的错误来自back管道的优先级(<\\),当您想要的是a |> f <| b时,(a |> f) <| b被看作是a |> (f <| b),它只是a |> (f b) (如在https://stackoverflow.com/a/39932313/4925216中所示)。

也就是说,你可以用这样的方式写些更易读的东西:

代码语言:javascript
复制
let getAllFiles (dir: DirectoryInfo) =
  let rec aux dir = [
    for file in getFiles dir -> file
    for subDir in getDirs dir do yield! aux subDir
  ]

  if dirExists dir
  then aux dir
  else raise <| NoDirectory "error"

这样,我们将递归部分与检查部分分离开来。

递归部分更简单、更易读,并且返回一个list,而不是最初想要的数组(我添加了一个getDirs)。

检查部分是用if完成的,因为true/false的匹配在这里不会增加值

并且只对初始参数执行,因为getDirs返回不存在的目录的可能性很小*

*即使有人在错误的时间删除了一个,但在这种情况下,你可以重写它

代码语言:javascript
复制
let rec getAllFiles (dir: DirectoryInfo) = [
  if dirExists dir then
    for file in getFiles dir -> file
    for subDir in getDirs dir do yield! getAllFiles subDir
]

这样,您甚至不需要引发错误,只需为一个不存在的目录获得一个空列表即可。

票数 1
EN

Stack Overflow用户

发布于 2016-10-08 02:17:45

如果需要seq,也可以使用EnumarateDirectories,不过对于IO,我会小心使用惰性集合。这将返回我的项目(子)目录中的所有56个文件:

代码语言:javascript
复制
open System.IO
let dir = DirectoryInfo __SOURCE_DIRECTORY__
dir.GetDirectories("*",SearchOption.AllDirectories) |> Array.collect (fun x -> x.GetFileSystemInfos()) 

如果您将Array.collect替换为Array.map,则顶级集合将是目录的集合(与我所拥有的完全相同)。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/39927484

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档