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
isO(1)
)的同时过滤非常大的数据集中的值。