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

时间:2015-03-06 17:45:31

标签: f# hashmap 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

我想要做的是构造一个哈希表,每个文件的字节数组作为键,文件名本身作为值。如果具有不同文件名的多个文件共享相同的bye数组,则它们是重复的,我的目标是删除重复的文件。

我查看了MSDN上的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的工作原因而被困在这里。谢谢。

1 个答案:

答案 0 :(得分:2)

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

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