F#中的列表展平

时间:2014-01-10 18:51:18

标签: f#

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

我的数据类型是val regEntries:RegistryKey列表

我希望它只是一个列表。

以下是我的代码:

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

3 个答案:

答案 0 :(得分:8)

尝试以下

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

答案 1 :(得分:5)

使用各种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的序列的新值以及表达式包含在中的事实方括号使其成为列表理解。

答案 2 :(得分:0)

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

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

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