Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/fsharp/3.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
F# 重复takeWhile调用的等价物:此函数是否有一个";标准;名称_F#_Functional Programming - Fatal编程技术网

F# 重复takeWhile调用的等价物:此函数是否有一个";标准;名称

F# 重复takeWhile调用的等价物:此函数是否有一个";标准;名称,f#,functional-programming,F#,Functional Programming,我有一个场景,标准的List.groupBy函数不是我想要的,但是我不知道这个函数的正确名称,因此很难搜索 我有一个'T类型的项目列表,以及一个'T->'k键生成函数。这些项在列表中已经有些“分组”在一起,因此当您通过键函数映射列表时,其结果往往会在一行中多次使用相同的键,例如[1;1;1;2;2;1;1;3;3;1;1]。我想要的是得到一个列表列表,其中内部列表包含键生成函数返回相同值的所有项——但它不应该将不同的1序列分组在一起 换句话说,假设我的数据是字符串列表,关键生成函数是String

我有一个场景,标准的
List.groupBy
函数不是我想要的,但是我不知道这个函数的正确名称,因此很难搜索

我有一个
'T
类型的项目列表,以及一个
'T->'k
键生成函数。这些项在列表中已经有些“分组”在一起,因此当您通过键函数映射列表时,其结果往往会在一行中多次使用相同的键,例如
[1;1;1;2;2;1;1;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"]]
换一种方式考虑:这就像获取列表的第一项并存储调用key函数的结果。然后使用
takeWhile(funx->keyfunx=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”;(2,[“to”;“of”],(3,[“and”;“for”;“the”])],
,但在这种情况下,我希望“a/e/i”、“o/u”和“i/o”列表保持分离,并且我不希望生成键返回的值出现在输出数据中)


也许这个函数没有一个标准名称。但是如果有,那是什么呢?

我有点晚了,你似乎找到了一个解决方案,而且似乎没有一个函数可以处理这个问题

为了迎接挑战,我试图找到一些可用的解决方案,并提出了以下建议(它们是否有效取决于读者):

开放系统
模块列表=
/// 
///通用列表扩展:
///给定一个比较器函数,列表将分块到子列表中
///当比较器发现差异时开始。
/// 
让chunkByPredicate(比较器:'T->'T->bool)列表=
让rec func(i:int,lst:'T list):'T list=
如果i>=lst.长度,则
List.empty
其他的
让我们先来看看
让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. 使用List.fold按字符串长度分块
让我们使用ListFold(数据:字符串列表)=
printfn“1.使用List.fold:”
资料
|>List.fold(乐趣(附件:字符串列表)s->
如果附件长度>0,则
let last=附件[附件长度-1]
设lastLength=last[0]。长度
如果lastLength=s.长度,则
List.append(acc |>List.take(acc.Length-1))[(last |>List.append[s])]
其他的
List.append acc[[s]]
其他的
[[s]]([]))
|>List.iter(printfn“%A”)
打印fn“”
// 2. 使用List.chunkByPredicate
让我们使用ListChunkByPredicate'a->bool,data:'a list)=
printfn“2.使用List.chunkByPredicate:”
数据
|>List.chunkByPredicate谓词
|>List.iter(printfn“%A”)
打印fn“”
[]
让主argv=
设data=[“a”;“e”;“i”;“to”;“of”;“o”;“u”;“for”;“the”;“i”;“o”]
使用列表折叠数据
使用ListChunkByPredicate((fun first s->first.Length=s.Length),数据)
设intData=[0..50]
使用ListChunkByPredicate((趣味优先n->first/10=n/10),intData)
Console.ReadLine()|>忽略
0

我认为没有标准名称。你应该继续写这个;您已经说过它很容易编写,您为函数编写的代码将用于记录它的功能。另请参见,它与您的函数类似,但属于泛型,我的意思是它可以与数组、列表和seq一起使用。也在中。由于与
列表.chunkBySize
相似,因此将其命名为
chunk
chunkBy
,如何。两者都创建一个列表列表,保留原始列表的顺序,另一个按大小分块,另一个按谓词分块。
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