Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Hash 我可以使用折叠(或其他类型的缩减)来处理这段代码吗?_Hash_F# - Fatal编程技术网

Hash 我可以使用折叠(或其他类型的缩减)来处理这段代码吗?

Hash 我可以使用折叠(或其他类型的缩减)来处理这段代码吗?,hash,f#,Hash,F#,我正试图重新点燃我对F#的了解。为了练习,我构建了一个计算F#中字符串散列的实现 这是我想出的代码: let XorWithHash b hash = hash ^^^ b let MultiplyByPrimeFactor hash = let Prime = 16777619un hash * Prime let GetNthByteOfString (s:string) n = if (n < Encoding.UTF8.GetByteCount(s

我正试图重新点燃我对F#的了解。为了练习,我构建了一个计算F#中字符串散列的实现

这是我想出的代码:

let XorWithHash b hash =
   hash ^^^ b

let MultiplyByPrimeFactor hash =
   let Prime = 16777619un   
   hash * Prime

let GetNthByteOfString (s:string) n =
   if (n < Encoding.UTF8.GetByteCount(s)) then Some(unativeint (Encoding.UTF8.GetBytes(s).[n])) else None


let GetFNV1a32 s =
   let rec transformString s n (acc:unativeint)=
      let b = GetNthByteOfString s n 
      match b with
      | Some b -> 
         XorWithHash b acc 
         |> MultiplyByPrimeFactor
         |> transformString s (n+1)
      | None -> acc

   let OffsetBasis = 2166136261un
   transformString s 0 OffsetBasis

let Main =
   let answer = GetFNV1a32 "Test String"
   answer
让XorWithHash b散列=
散列^b
让多重优先因子散列=
设素数=16777619un
散列*素数
让GetNthByteOfString(s:string)n=
如果是(n
XORWITHB acc
|>多重优先因子
|>转换字符串s(n+1)
|无->acc
出租抵销基准=2166136261牛顿
转换字符串s 0偏移基准
让主管道=
let answer=GetFNV1a32“测试字符串”
答复

它工作正常,我对此很满意。我的问题是:如果我可以使用折叠或其他形式的reduce,我想我可以简化
transformString
的实现,但我似乎不能完全理解它。有谁能帮我实现一个使用折叠或缩减之类的transformString吗?或者这是我可能得到的最好的吗?

你当然可以,这就是它看起来的样子:

let GetFNV1a32 (s: string) =
    let offsetBasis = 2166136261un
    // We only have to get the bytes once; now we have an entire array that we can perform monadic operations on
    Encoding.UTF8.GetBytes s
    // Array.fold's signature is ('State -> 't -> 'State) -> 'State -> 't[] -> 'State
    // So here 'State is unativeint, and 't is byte, which is the current item of the byte[]. We can just transform it in one go to our output value, which becomes the value of acc the next time around.
    |> Array.fold (fun acc byt -> MultiplyByPrimeFactor (XorWithHash (unativeint byt) acc))
        offsetBasis   // initial value
这里有一个快速测试来证明它是有效的,假设
GetFNV1a32\u old
是OP:

let xs =
    [for str in ["TestString"; "Test String"; "foo BAR"; "BÄz qúåx"] do
        let old, neww = GetFNV1a32_old str, GetFNV1a32 str
        yield old, neww, (sprintf "does old = neww? %b" (old = neww))]
其结果是:

val xs : (unativeint * unativeint * string) list =
   [(17683775798505137816un, 17683775798505137816un, "is old = neww? true");
    (3444292159790811978un, 3444292159790811978un, "is old = neww? true");
    (17137498406203898314un, 17137498406203898314un, "is old = neww? true");
    (13890330577974722754un, 13890330577974722754un, "is old = neww? true")]

因为我现在没有时间回答这个问题,所以有一个简短的评论:您的代码当前是O(N^2),因为它为字符串的每个字节调用一次
Encoding.UTF8.GetBytes(s)
(一个O(N)操作)。最好在
GetFNV1a32
内部调用
GetBytes
,然后将
transformString
函数转换为
transformByteArray
函数;它是一个在初始化时计算一次的值。要使其成为函数,必须使用
let Main()=。。。etc etc
。我的F肯定生锈了!谢谢