【问题标题】:List flattening in F#F# 中的列表展平
【发布时间】:2014-01-10 18:51:18
【问题描述】:

我是 F# 的新手,并试图在 F# 中重写我们的一个应用程序以尝试在此过程中学习它,但我在扁平化列表时遇到了一些麻烦。我已经搜索并找到了几个答案,但我似乎无法让它们中的任何一个起作用。

我的数据类型是 val regEntries: RegistryKey list list

我希望它只是一个列表。

下面是我的代码:

namespace DataModule

module RegistryModule =
    open Microsoft.Win32

let regEntries = 
    ["SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"]
    |> List.map (fun x -> Microsoft.Win32.Registry.LocalMachine.OpenSubKey(x))
    |> List.map(fun k -> List.ofArray(k.GetSubKeyNames()) |> List.map (fun x -> k.OpenSubKey(x)) |> List.filter (fun x -> x.GetValue("ProductId") <> null))

【问题讨论】:

标签: f#


【解决方案1】:

试试下面的

let regEntries = 
    ["SOFTWARE\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"; "SOFTWARE\\Wow6432Node\\Microsoft\\Windows\\CurrentVersion\\Uninstall\\"]
    |> Seq.map (fun x -> Microsoft.Win32.Registry.LocalMachine.OpenSubKey(x))
    |> Seq.map(fun k -> 
       (k.GetSubKeyNames()) 
       |> Seq.map (fun x -> k.OpenSubKey(x)) 
       |> Seq.filter (fun x -> x.GetValue("ProductId") <> null)))
    |> Seq.concat
    |> List.ofSeq

Seq.concat 方法可用于将T list list 转换为T list。请注意,我将您的很多 List. 呼叫转换为 Seq. 呼叫。直到最后似乎都不需要创建实际的list,因此我将其保留为简单的seq

【讨论】:

  • 请注意,您可以将管道Seq.map f |&gt; Seq.concat替换为单个部分函数Seq.collect f,请参阅doc
  • 您也可以将Seq.map (fun x -&gt; k.OpenSubKey(x)) 替换为Seq.map k.OpenSubKey。对 OpenSubKey 的其他调用也是如此。
【解决方案2】:

使用各种 mapfilter 函数绝对是一种选择 - 而且效果很好(它也是学习函数抽象的好方法)。

但是,您也可以使用序列推导,这是一种很好的语法糖,可以让编写这类任务更容易一些(在我看来)。要执行与 Jared 答案中发生的相同的事情,您可以编写:

let subKeys = 
  [@"SOFTWARE\Microsoft\Windows\CurrentVersion\Uninstall\"; //"
   @"SOFTWARE\Wow6432Node\Microsoft\Windows\CurrentVersion\Uninstall\"] // "

let regEntries = 
  [ for subKey in subKeys do     
      let k = Microsoft.Win32.Registry.LocalMachine.OpenSubKey(subKey)
      for name in k.GetSubKeyNames() do
        let x = k.OpenSubKey(name) 
        if x.GetValue("ProductId") <> null then
          yield x ]

嵌套简单地变为嵌套for 循环,过滤使用if 表示 - 生成序列的新值,您可以使用yield 并且表达式括在方括号中的事实使其成为 列表理解。

【讨论】:

    【解决方案3】:

    请注意,如果您发现这个问题正在寻找一种基本的扁平化方法:

    let flatten (source : 'T seq seq) :'T seq =
        System.Linq.Enumerable.SelectMany(source, id)
    

    这是使用 F# 的 id function 对 .net SelectMany 的基本调用。

    【讨论】:

      猜你喜欢
      • 2011-04-30
      • 1970-01-01
      • 2012-03-19
      • 2018-04-15
      • 2021-09-07
      • 2018-07-04
      • 2022-11-28
      • 1970-01-01
      相关资源
      最近更新 更多