测试投影在 F# 序列上是否均匀
Testing if a projection is uniform over an F# sequence
我想检查序列上的投影在 F# 中是否具有统一值。
这是我的:
module Seq =
let isUniformBy (f) (xs : seq<_>) =
let l =
xs
|> Seq.map f
|> Seq.distinct
|> Seq.truncate 2
|> Seq.length
l < 2
let isUniform xs = isUniformBy id xs
printfn "%b" <| Seq.isUniformBy id [ 1; 2; 3 ] // false
printfn "%b" <| Seq.isUniformBy id [ 1; 1; 1 ] // true
printfn "%b" <| Seq.isUniformBy id [ ] // true
printfn "%b" <| Seq.isUniformBy id [ 1; 1 ] // true
printfn "%b" <| Seq.isUniformBy id [ 1; 1; 2 ] // false
printfn "%b" <| Seq.isUniformBy id [ 1; 2 ] // false
printfn "%b" <| Seq.isUniformBy (fun x -> x % 2) [ 2; 4; 6; 8 ] // true
我想知道是否已经有内置函数?
如果没有,实现它的最佳方法是什么?
您可以使用 Seq.distinctBy
(link), and then simplify slightly more via Seq.tryExactlyOne
(link) 组合前两个调用,尽管它随后会报告 false
为空序列:
let isUniformBy f xs =
xs
|> Seq.distinctBy f
|> Seq.tryExactlyOne
|> Option.isSome
我们可以将问题简化为比较相邻元素 - 因为为了统一起见,我们不能有任何与前面的元素不同的元素。
这意味着我们只需要检查是否存在这样的一对——我们只需要枚举序列直到找到一对。
let isUniform xs =
xs
|> Seq.pairwise
|> Seq.exists (fun (a, b) -> a <> b)
|> not
let isUniformBy (f) (lst : seq<_>) =
lst |> Seq.map f |> isUniform
基本方法是 isUniform
,因此我们可以将投影序列从 isUniformBy
传递给它,避免通过 id
。此外,我们只使用 O(1) space.
测试
assert( Seq.isUniformBy id [ 1; 2; 3 ] = false)
assert( Seq.isUniformBy id [ 1; 1; 1 ] = true)
assert( Seq.isUniformBy id [ ] = true)
assert( Seq.isUniformBy id [ 1; 1 ] = true)
assert( Seq.isUniformBy id [ 1; 1; 2 ] = false)
assert( Seq.isUniformBy id [ 1; 2 ] = false)
assert( Seq.isUniformBy (fun x -> x % 2) [ 2; 4; 6; 8 ] = true)
如果这不是最好的(即最易读、最高效),而是最短的方法,我会按照 OP 的方法稍微优化一下:
module Seq =
let isUniformBy f x = Seq.groupBy f x |> Seq.length < 2
// val isUniformBy : f:('a -> 'b) -> x:seq<'a> -> bool when 'b : equality
[ id, [ 1; 2; 3 ] // false
id, [ 1; 1; 1 ] // true
id, [ ] // true
id, [ 1; 1 ] // true
id, [ 1; 1; 2 ] // false
id, [ 1; 2 ] // false
(fun x -> x % 2), [ 2; 4; 6; 8 ]] // true
|> Seq.iter ((<||) Seq.isUniformBy >> printfn "%b")
我想检查序列上的投影在 F# 中是否具有统一值。
这是我的:
module Seq =
let isUniformBy (f) (xs : seq<_>) =
let l =
xs
|> Seq.map f
|> Seq.distinct
|> Seq.truncate 2
|> Seq.length
l < 2
let isUniform xs = isUniformBy id xs
printfn "%b" <| Seq.isUniformBy id [ 1; 2; 3 ] // false
printfn "%b" <| Seq.isUniformBy id [ 1; 1; 1 ] // true
printfn "%b" <| Seq.isUniformBy id [ ] // true
printfn "%b" <| Seq.isUniformBy id [ 1; 1 ] // true
printfn "%b" <| Seq.isUniformBy id [ 1; 1; 2 ] // false
printfn "%b" <| Seq.isUniformBy id [ 1; 2 ] // false
printfn "%b" <| Seq.isUniformBy (fun x -> x % 2) [ 2; 4; 6; 8 ] // true
我想知道是否已经有内置函数? 如果没有,实现它的最佳方法是什么?
您可以使用 Seq.distinctBy
(link), and then simplify slightly more via Seq.tryExactlyOne
(link) 组合前两个调用,尽管它随后会报告 false
为空序列:
let isUniformBy f xs =
xs
|> Seq.distinctBy f
|> Seq.tryExactlyOne
|> Option.isSome
我们可以将问题简化为比较相邻元素 - 因为为了统一起见,我们不能有任何与前面的元素不同的元素。
这意味着我们只需要检查是否存在这样的一对——我们只需要枚举序列直到找到一对。
let isUniform xs =
xs
|> Seq.pairwise
|> Seq.exists (fun (a, b) -> a <> b)
|> not
let isUniformBy (f) (lst : seq<_>) =
lst |> Seq.map f |> isUniform
基本方法是 isUniform
,因此我们可以将投影序列从 isUniformBy
传递给它,避免通过 id
。此外,我们只使用 O(1) space.
测试
assert( Seq.isUniformBy id [ 1; 2; 3 ] = false)
assert( Seq.isUniformBy id [ 1; 1; 1 ] = true)
assert( Seq.isUniformBy id [ ] = true)
assert( Seq.isUniformBy id [ 1; 1 ] = true)
assert( Seq.isUniformBy id [ 1; 1; 2 ] = false)
assert( Seq.isUniformBy id [ 1; 2 ] = false)
assert( Seq.isUniformBy (fun x -> x % 2) [ 2; 4; 6; 8 ] = true)
如果这不是最好的(即最易读、最高效),而是最短的方法,我会按照 OP 的方法稍微优化一下:
module Seq =
let isUniformBy f x = Seq.groupBy f x |> Seq.length < 2
// val isUniformBy : f:('a -> 'b) -> x:seq<'a> -> bool when 'b : equality
[ id, [ 1; 2; 3 ] // false
id, [ 1; 1; 1 ] // true
id, [ ] // true
id, [ 1; 1 ] // true
id, [ 1; 1; 2 ] // false
id, [ 1; 2 ] // false
(fun x -> x % 2), [ 2; 4; 6; 8 ]] // true
|> Seq.iter ((<||) Seq.isUniformBy >> printfn "%b")