如何简化F#数组中不存在于另一个数组中的元素的过滤?

时间:2015-11-10 01:01:01

标签: f#

我有2个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
    |]

1 个答案:

答案 0 :(得分:3)

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

  1. 获取不同的CallNumbers(如果它们不是已经区分,否则只使用原始数组;不确定是否设置了一个集合或数组[可能会引起关注])
  2. 通过CallID中的CallNumber对您的工作项进行分组;给你一个>>> fmt=MyFormatter('">>{{{0}}} KeyError<<"') >>> fmt.format("{bond}, {james} {bond}", bond='bond', james='james') 'bond, james bond' >>> fmt.format("{bond}, {james} {bond}", bond='bond') 'bond, ">>{james} KeyError<<" bond'
  3. 过滤以仅保留不在步骤1中定义的数组/集中的键(调用号)。
  4. 最后“加入”工作项并使其成为数组
  5. 我使用Seq避免在每一步创建数组(内存问题),并且在(对我来说)更简单的方式中重写了另一个函数。

    seq<string * seq<WorkItem>>