F#:如何识别哈希表中具有多个值的键?

F#: How to identify keys that have multiple values in a HashTable?

我目前正在开发一个初学者项目来实现我自己的重复文件查找器。这是我第一次使用.NET 语言,所以我对.NET API 仍然非常陌生。

这是我到目前为止编写的代码:

open System
open System.IO
open System.Collections.Generic

let directory = @somePath

let getAllFiles (directory : string) =
    Directory.GetFiles(directory)

let getFileInfo (directory : string) =
    directory
    |> getAllFiles
    |> Seq.map (fun eachFile -> (eachFile, new FileInfo(eachFile)))

let getFileLengths (directory: string) =
    directory
    |> getFileInfo
    |> Seq.map (fun (eachFile, eachFileInfo : FileInfo) -> (eachFile, eachFileInfo.Length))

// If two files have the same lengths, they might be duplicates of each other.
let groupByFileLengths (directory: string) =
    directory
    |> getFileLengths
    |> Seq.groupBy snd
    |> Seq.map (fun (fileLength, files) -> fileLength, files |> Seq.map fst |> List.ofSeq)

let findGroupsOfTwoOrMore (directory: string) =
    directory
    |> groupByFileLengths
    |> Seq.filter (snd >> List.length >> (<>) 1)

let constructHashtable (someTuple) =
    let hashtable = new Hashtable()
    someTuple
    |> Seq.iter hashtable.Add
    hashtable

let readAllBytes (tupleOfFileLengthsAndFiles) =
    tupleOfFileLengthsAndFiles
    |> snd
    |> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
    |> constructHashtable

我想做的是以每个文件的字节数组为键,文件名本身为值构造一个散列table。如果多个不同文件名的文件共享同一个 bye 数组,那么它们就是重复的,我的目标是删除重复的文件。

我查看了 MSDN 上的 Hashtable 命名空间,但没有识别包含多个值的 hashtable 键的方法。

编辑:这是我尝试实现 MD5:

let readAllBytesMD5 (tupleOfFileLengthsAndFiles) =
    let md5 = MD5.Create()
    tupleOfFileLengthsAndFiles
    |> snd
    |> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
    |> Seq.map (fun (byteArray, eachFile) -> (md5.ComputeHash(byteArray), eachFile))
    |> Seq.map (fun (hashCode, eachFile) -> (hashCode.ToString, eachFile))

请指教我如何改进和继续,因为我因为没有牢牢掌握 MD5 的工作原理而被困在这里。谢谢。

Hashtable 不支持同一键的多个值 - 当您尝试使用同一键添加第二个条目时会出现异常。它也是无类型的,您应该几乎总是喜欢类型化的可变 System.Collections.Generic.Dictionary 或不可变的 F# Map.

您要找的是 Map<byte array, Set<string>>。这是我的看法:

let buildMap (paths: string array) =
    paths
    |> Seq.map (fun eachFile -> (File.ReadAllBytes eachFile, eachFile))
    |> Seq.groupBy fst
    |> Seq.map (fun (key, items) ->
        key, items |> Seq.map snd |> Set.ofSeq)
    |> Map.ofSeq

顺便说一句,除非您比较的是非常非常小的文件,否则使用整个文件内容作为关键字不会让您走得太远。您可能希望研究为这些文件生成校验和并改为使用它们。