尝试过滤掉不在另一个序列中的序列中的值

时间:2018-06-18 19:05:06

标签: f#

我正在尝试过滤掉序列中的值,这些值不在另一个序列中。我非常确定我的代码是有效的,但是在我的计算机上运行需要很长时间,因此我不确定,所以我在这里看看社区的想法。

代码如下:

let statezip =
    StateCsv.GetSample().Rows
    |> Seq.map (fun row -> row.State)
    |> Seq.distinct

type State = State of string

let unwrapstate (State s) = s
let neededstates (row:StateCsv) = Seq.contains (unwrapstate row.State) statezip

我正在通过requiredstates函数进行过滤。我这样做的方式有问题吗?

let datafilter =
    StateCsv1.GetSample().Rows
    |> Seq.map (fun row -> row.State,row.Income,row.Family)
    |> Seq.filter neededstates
    |> List.ofSeq

我认为它应该用真值来过滤序列,因为requiredstates函数是一个bool。 StateCsv和StateCsv1具有相同的确切结构,但来自不同年份。

1 个答案:

答案 0 :(得分:5)

对序列和列表contains的评估可能很慢。对于要检查集合中是否存在元素的情况,F#Set类型是理想的。您可以使用Set.ofSeq将序列转换为集合,然后在集合上运行逻辑。以下示例使用1到10000之间的数字,然后使用序列和集合通过检查值不在偶数集合中来将结果过滤为仅奇数。

使用序列:

let numberSeq = {0..10000}
let evenNumberSeq = seq { for n in numberSeq do if (n % 2 = 0) then yield n }

#time
numberSeq |> Seq.filter (fun n -> evenNumberSeq |> Seq.contains n |> not) |> Seq.toList
#time

这对我来说大约需要1.9秒。

使用集合:

let numberSet = numberSeq |> Set.ofSeq
let evenNumberSet = evenNumberSeq |> Set.ofSeq

#time
numberSet |> Set.filter (fun n -> evenNumberSet |> Set.contains n |> not)
#time

这仅运行0.005秒。希望您可以在执行contains操作之前将序列具体化,从而获得此级别的加速。