F#fsharp从两个数组中查找字符串“开头为”的快速方法

时间:2018-10-30 06:51:50

标签: arrays performance parallel-processing f#

我对大型阵列(每个50k)的性能有疑问。在给定两个数组的情况下,找到以另一个字符串开头的字符串的最快方法是什么?我已经尝试了不同的方法,但是下面的代码似乎尽我所能。

let findFile (f:string, p:string, pc:string, pcn:string) =
    f.StartsWith(p + "-" + pc) || 
    f.StartsWith(p + "_" + pc) ||
    f.StartsWith(p + "-" + pcn) ||
    f.StartsWith(p + "_" + pcn)

products
|> Array.Parallel.map (fun i p ->
    allFiles |> Array.Parallel.map (fun f ->
        if findFile (f.Filename, p.Style, p.ColorCode, p.ColorName)
        then {p with Filename = f.Filename }
        else p
    ))

谢谢。

1 个答案:

答案 0 :(得分:1)

首先,我建议通过拆分两个部分来清理文件名,并尽可能删除其余部分:

  • '-''_'字符分割文件名,以便将(样式*颜色)的元组而不是字符串进行两次比较。另外,请尽可能区分使用颜色名称中的颜色代码和分成2个数组。

现在您有2个选择:使用字典或对值进行排序

  • 字典:将较长的列表放入字典中。扫描较短的列表以查找值。字典使用哈希表,这使它们非常有效,并且比较也非常快。这就要求您仅将样式和颜色代码/名称用作键,而将其余的字符串排除在外。

解决方案如下:

let dict () =
    let dict = new Dictionary<_, _>()
    allFiles |> Seq.iter (fun f -> f.Filename.Split '-' |> fun a -> dict.Add((a.[0], a.[1]), f) )
    products
    |> Array.Parallel.map (fun p -> 
        let vRef = ref { Filename = "" }
        if dict.TryGetValue((p.Style, p.ColorCode) , vRef)
        then {p with Filename = (!vRef).Filename }
        else p
    )

如果不可能,请考虑:

  • 排序两个列表:产品和文件名。同时扫描两个有序列表以及一个索引,每个索引每次仅使较低的值前进。

还有一件事: 如果仍要进行字符串比较,则应考虑使用非常有效的已编译Regex。您的正则表达式可能类似于:^code[-_](red|FF0000),它将匹配4个值中的任何一个:

  • code-red
  • code_red
  • code-FF0000
  • code_FF0000

这是使用编译的Regex的方式:

let regex = new Regex(sprintf "^%s[-_](%s|%s)" p.Style p.ColorCode p.ColorName, RegexOptions.Singleline + RegexOptions.Compiled)
for i in 1..30 do
    if regex.IsMatch(sprintf "code-%d" i) then printfn "%A" i