我的情况是标准List.groupBy
功能不是我想要的,但我不知道这个功能的正确名称,因此难以搜索对
我有一个'T
类型的项目列表,以及一个'T -> 'k
密钥生成函数。这些项目已经有点"分组"在列表中一起使用,这样当你通过键功能映射列表时,其结果往往会连续几次具有相同的键,例如, [1; 1; 1; 2; 2; 1; 1; 3; 3; 3; 1; 1]
。我想要的是获得一个列表列表,其中内部列表包含密钥生成函数返回相同值的所有项目 - 但它不应该将1的不同序列组合在一起。
换句话说,我的数据是一个字符串列表,密钥生成函数是String.length
。所以输入是:
["a"; "e"; "i"; "to"; "of"; "o"; "u"; "and"; "for"; "the"; "I"; "O"]
我想要的输出是:
[["a"; "e"; "i"]; ["to"; "of"]; ["o"; "u"]; ["and"; "for"; "the"]; ["I"; "O"]]
以另一种方式来思考:这就像获取列表的第一项并存储调用键函数的结果一样。然后,您使用takeWhile (fun x -> keyFun x = origKeyFunResult)
生成第一个细分。然后当takeWhile
停止返回值时,您会记录它何时停止,并且keyFun x
的值在第一个值上没有返回原始结果 - 并从那里继续。 (除了那将是O(N * M),其中M是序列的数量,并且在许多情况下将转换为O(N ^ 2) - 而应该可以在O(N)时间内实现该函数)。
现在,我可以很容易地编写该功能。这不是问题。我想知道的是这个函数是否有标准的名称。因为我认为它会被称为groupBy
,但那是别的东西。 (List.groupBy String.length
会返回[(1, ["a"; "e"; "i"; "o"; "u"; "I"; "O"]); (2, ["to"; "of"]), (3, ["and"; "for"; "the"])]
,但在这种情况下我想要的是" a / e / i"," o / u"和& #34; I / O"列表保持分离,并且我不希望生成密钥的值返回到输出数据中。
可能没有此功能的标准名称。但如果有,那是什么?
答案 0 :(得分:0)
我有点晚了,似乎你找到了一个解决方案,而且似乎没有单一的功能可以解决这个问题。
为了应对这一挑战,我试图找到一些可用的解决方案并提出以下建议(无论它们是否有效都是读者需要的):
open System
module List =
/// <summary>
/// Generic List Extension:
/// Given a comparer function the list will be chunked into sub lists
/// starting when ever comparer finds a difference.
/// </summary>
let chunkByPredicate (comparer : 'T -> 'T -> bool) list =
let rec func (i : int, lst : 'T list) : 'T list list =
if i >= lst.Length then
List.empty
else
let first = lst.[i]
let chunk = lst |> List.skip(i) |> List.takeWhile (fun s -> comparer first s)
List.append [chunk] (func((i + chunk.Length), lst))
func (0, list) |> List.where (fun lst -> not (List.isEmpty lst))
// 1. Using List.fold to chunk by string length
let usingListFold (data : string list) =
printfn "1. Using List.fold: "
data
|> List.fold (fun (acc : string list list) s ->
if acc.Length > 0 then
let last = acc.[acc.Length - 1]
let lastLength = last.[0].Length
if lastLength = s.Length then
List.append (acc |> List.take (acc.Length - 1)) [(last |> List.append [s])]
else
List.append acc [[s]]
else
[[s]]) ([])
|> List.iter (printfn "%A")
printfn ""
// 2. Using List.chunkByPredicate
let usingListChunkByPredicate<'a> (predicate : 'a -> 'a -> bool, data : 'a list) =
printfn "2. Using List.chunkByPredicate: "
data
|> List.chunkByPredicate predicate
|> List.iter (printfn "%A")
printfn ""
[<EntryPoint>]
let main argv =
let data = ["a"; "e"; "i"; "to"; "of"; "o"; "u"; "and"; "for"; "the"; "I"; "O"]
usingListFold data
usingListChunkByPredicate<string>((fun first s -> first.Length = s.Length), data)
let intData = [0..50]
usingListChunkByPredicate<int>((fun first n -> first / 10 = n / 10), intData)
Console.ReadLine() |> ignore
0