F# 尝试筛选出序列中不在其他序列中的值

F# 尝试筛选出序列中不在其他序列中的值,f#,F#,我试图从一个序列中筛选出不在另一个序列中的值。我很确定我的代码是有效的,但在我的计算机上运行需要很长时间,因此我不确定,所以我来这里看看社区的想法 代码如下: let statezip = StateCsv.GetSample().Rows |> Seq.map (fun row -> row.State) |> Seq.distinct type State = State of string let unwrapstate (State s) =

我试图从一个序列中筛选出不在另一个序列中的值。我很确定我的代码是有效的,但在我的计算机上运行需要很长时间,因此我不确定,所以我来这里看看社区的想法

代码如下:

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
我通过neededstates函数进行过滤。我这样做有什么问题吗

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

我认为它应该根据真值过滤序列,因为neededstates函数是bool。StateCsv和StateCsv1具有相同的精确结构,尽管年份不同。

对序列和列表中的
包含的
进行评估可能会很慢。对于要检查集合中是否存在元素的情况,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秒。希望您能在执行
包含
操作之前将序列具体化为集合,从而获得这一级别的加速。

正在处理的CSV文件中大约有多少行?数万个STEN是使用
集合
的好选择。如果序列非常小,那么将序列具体化为一个集合的成本将大于对序列执行
包含
的开销。另一方面,如果序列非常大,则可能无法将整个序列具体化为一个集合。然而,成千上万的人在这个范围内,使用
set.ofSeq
将序列具体化为set.ofSeq将提供相当大的加速。很好,我很欣赏这一见解。如果我使用上面提到的contains函数进行过滤,那么我认为它可以工作吗?是的,如果标准的相等比较适用于序列中的对象,那么
contains
函数应该可以工作。对于较大的序列来说,速度会很慢。好的,很好。在我放弃之前,这个功能运行了15分钟。这太荒谬了。我会试试这个。昂贵的操作只是
包含的
,因此当将
numberSeq
evenNumberSet
相结合时,它应该运行得更快,这也巧妙地避免了创建
numberSet
的(未测量的)开销。通过这种方式,您可以在保留
O(N)
特征(
Set.contains
is
O(1)
)的同时过滤非常大的数据集中的值。