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#数组中不';不存在于另一个数组中?_F# - Fatal编程技术网

如何简化F#数组中不';不存在于另一个数组中?

如何简化F#数组中不';不存在于另一个数组中?,f#,F#,我有两个F#数组要比较。对于其中一个函数,我必须找到数组1中的所有元素,这些元素在数组2中没有具有相同键字段的元素 我设法弄到了一些有用的东西,但我必须承认我现在读起来有点眼花了。我很同情开发人员,他们以后将不得不修改这个 在findWorkItemToClose函数中是否有一种更简单、更可读的方式来表达这一点 /// Gets the ICCM call number given a work item reference id. The reference id may have a das

我有两个F#数组要比较。对于其中一个函数,我必须找到数组1中的所有元素,这些元素在数组2中没有具有相同键字段的元素

我设法弄到了一些有用的东西,但我必须承认我现在读起来有点眼花了。我很同情开发人员,他们以后将不得不修改这个

findWorkItemToClose
函数中是否有一种更简单、更可读的方式来表达这一点

/// Gets the ICCM call number given a work item reference id. The reference id may have a dash number suffix on the call number.
let getIccmCallNumberFromReference (referenceId:string) =
    if referenceId.Contains("-") then
        referenceId.Substring(0, referenceId.IndexOf("-"))
    else
        referenceId

/// Gets the TFS work items where the ReferenceId no longer exists in the set of open Iccm calls.
let findWorkItemsToClose (allWorkItems:WorkItem[]) (iccmCalls:Iccm.IccmCall[]) =
    let openStates = Set.ofList ["New"; "Approved"; "Commited"]
    let openWorkItems = allWorkItems |> Array.filter (fun wi -> Set.contains wi.State openStates)
    openWorkItems
    |> Array.filter(fun wi -> 
        not (iccmCalls 
                |> Array.exists (fun ic -> 
                    ic.CallNumber = getIccmCallNumberFromReference (wi.Fields.["ReferenceId"].Value.ToString()))))
更新:使用数组理解发布备选版本1(来自答案中的建议)和备选版本2

/// ALT 1: Gets the TFS work items where the ReferenceId no longer exists in the set of open Iccm calls.
let findWorkItemsToClose1 (allWorkItems : WorkItem []) (iccmCalls : Iccm.IccmCall []) =
  let callNumbers = iccmCalls |> Array.map (fun ic -> ic.CallNumber) |> Set.ofArray
  let openStates = Set.ofList ["New"; "Approved"; "Commited"]
  let openWorkItems = allWorkItems |> Array.filter (fun wi -> Set.contains wi.State openStates)

  openWorkItems
  |> Seq.groupBy (fun wi -> getIccmCallNumberFromReference(wi.Fields.["ReferenceId"].Value.ToString()))
  |> Seq.filter (fun (callNumber, _) -> not (Set.contains callNumber callNumbers))
  |> Seq.collect snd
  |> Seq.toArray

/// ALT 2: Gets the TFS work items where the ReferenceId no longer exists in the set of open Iccm calls.
let findWorkItemsToClose2 (allWorkItems : WorkItem []) (iccmCalls : Iccm.IccmCall []) =
    let iccmCallNumbers = iccmCalls |> Array.map (fun ic -> ic.CallNumber) |> Set.ofArray
    let openStates = Set.ofList ["New"; "Approved"; "Commited"]
    let openWorkItems = allWorkItems |> Array.filter (fun wi -> Set.contains wi.State openStates)

    [|
        for workItem in openWorkItems do
            let callNumberOnWorkItem = getIccmCallNumberFromReference(workItem.Fields.["ReferenceId"].Value.ToString())
            if not (Set.contains callNumberOnWorkItem iccmCallNumbers) then
                yield workItem
    |]

不是100%确定这是你想要的,但如果我是对的,你可以:

  • 获取不同的调用号(如果它们还没有不同,则使用原始数组;不确定是否将其设置为集合或数组[perf concern maybe])
  • 根据引用ID中的CallNumber对工作项进行分组;给你一个
    seq
  • 筛选以仅保留不在步骤1中定义的数组/集合中的键(callnumber)
  • 最后“连接”回工作项并使其成为一个数组
  • 我使用Seq来避免在每一步创建数组(内存问题),并且还以一种(对我来说)更简单的方式重写了另一个函数

    let getIccmCallNumberFromReference (referenceId : string) =
      match referenceId.IndexOf "-" with
        -1    -> referenceId
      |  0    -> "" // to be consistent with the original function
      | index -> referenceId.[.. index - 1]
    
    let findWorkItemsToClose (allWorkItems : WorkItem []) (iccmCalls : Iccm.IccmCall []) =
       // see comments if you choose to use a set instead of an array
      let callNumbers = iccmCalls |> Array.distinctBy (fun ic -> ic.CallNumber) // |> Set.ofArray
    
      allWorkItems
      |> Seq.groupBy (fun wi -> getIccmCallNumberFromReference(wi.Fields.["ReferenceId"].Value.ToString()))
      |> Seq.filter (fun (callNumber, _) -> not (Array.contains callNumber callNumbers)) // replace Array.contains by Set.contains
      |> Seq.collect snd
      |> Seq.toArray
    

    这些都是很好的改进!iccmCalls.CallNumber是唯一的,所以我只是将其转换为Set。我非常喜欢Set.contains的使用,它使exists过滤器更容易掌握。getIccmCallNumberFromReference的新版本运行良好。对我来说,用[..index-1]索引字符串是新的。比子字符串更简洁。