F#从字符串[]列表

时间:2017-03-29 09:26:43

标签: arrays list f# duplicates

我有一个程序导致[]列表,我试图从列表中删除近似重复的数组。列表的一个例子是......

[
   [|
      "Jackson";
      "Stentzke";
      "22";
      "001"
    |];
    [|
      "Jackson";
      "Stentzke";
      "22";
      "002"
    |];
    [|
      "Alec";
      "Stentzke";
      "18";
      "003"
    |]
]

基本上我试图编写一个可以读取列表并删除几乎相同数据的所有示例的函数。所以最终返回的[]列表应该看起来像......

[
    [|
      "Alec";
      "Stentzke";
      "18";
      "003"
    |]
]

我已经尝试了许多功能来尝试获取此结果或与其接近的可以使用的结果。我目前的尝试是......

let removeDuplicates (arrayList: string[]list) =
    let list = arrayList|> List.map(fun aL -> 
        let a = arrayList|> List.map(fun aL2 -> 
                try
                    match (aL.GetValue(0).Equals(aL2.GetValue(0))) && (aL.GetValue(2).Equals(aL2.GetValue(2))) && (aL.GetValue(3).Equals(aL2.GetValue(3))) with
                    | false -> aL2
                    | _ -> [|""|]
                with
                | ex -> [|""|]
            )
        a 
                                              )
    list |> List.concat |> List.distinct

但是所有这些都是input []列表中的反转版本。

有谁知道如何从列表中删除近似重复的数组?

3 个答案:

答案 0 :(得分:2)

我相信您的代码和评论不能很好地匹配。考虑到您的评论“第一,第二和第三个值是相同的”,我相信这可以让您走在正确的轨道上:

let removeDuplicates (arrayList: string[]list) =
    arrayList |> Seq.distinctBy (fun elem ->  (elem.[0] , elem.[1] , elem.[2]))

对输入数据的结果是一个包含以下内容的双元素列表:

[
 [|
  "Jackson";
  "Stentzke";
  "22";
  "001"
 |];
 [|
  "Alec";
  "Stentzke";
  "18";
  "003"
 |]
]

答案 1 :(得分:1)

您应该根据您认为相同的字段创建字典/地图,然后删除任何重复的出现。这是一种简单而机械的方式,假设xs是您在上面指定的List:

type DataRec = { key:string
                 fname:string
                 lname:string
                 id1:string
                 id2:string}

let dataRecs = xs |> List.map (fun x -> {key=x.[0]+x.[1]+x.[2];fname=x.[0];lname=x.[1];id1=x.[2];id2=x.[3]})

dataRecs |> Seq.groupBy (fun x -> x.key) 
         |> Seq.filter (fun x -> Seq.length (snd x) = 1)
         |> Seq.collect snd
         |> Seq.map (fun x -> [|x.fname;x.lname;x.id1;x.id2|])
         |> Seq.toList

输出:

  

val it:string [] list = [[|“Alec”; “Stentzke”; “18”; “003” |]]

它基本上从前三个项创建一个键,由它组成的组,过滤掉2个中的任何一个,然后映射回一个数组。

答案 2 :(得分:1)

使用一些Linq:

let comparer (atMost) = 
    { new System.Collections.Generic.IEqualityComparer<string[]> with
            member __.Equals(a, b) = 
                Seq.zip a b
                    |> Seq.sumBy (fun (a',b') -> System.StringComparer.InvariantCulture.Compare(a', b') |> abs |> min 1)
                    |> ((>=) atMost)
            member __.GetHashCode(a) = 1
    }

System.Linq.Enumerable.GroupBy(data, id, comparer 1)
    |> Seq.choose (fun g -> match Seq.length g with | 1 -> Some g.Key | _ -> None)

比较器允许两个数组之间存在atMost : int个差异。