【问题标题】:F# idiomatic way of determining if all (key*value) list entries sharing key have same singular distinct valueF#确定共享键的所有(键*值)列表条目是否具有相同的奇异值的惯用方法
【发布时间】:2016-01-10 08:16:34
【问题描述】:

给定一组int*string的字典,其中第一个是“主要”,我想回答这个问题:

对于所有其他字典,它们全部是否具有与主字典相同的键值?

我目前通过以下方式实现了这一目标:

let allSame = primary @ remaining
              |> Seq.groupBy (fun (pos, _) -> pos)
              |> Seq.map (fun (pos, items) -> (pos, items |> Seq.map (fun (_, name) -> name) |> Seq.distinct |> List.ofSeq))
              |> Seq.exists (fun (_, names) -> names.Length > 1))

我想知道是否有更惯用的方法来实现这一点?

在分组int * (int * string) list 中重复pos,然后必须减少到int * string list 似乎有点多余,但不幸的是groupBy 不提供价值投影过载。


编辑

给定一堆简化结构的项目(字段){SortOrder:int;Name:string;...}

我要去:Field list -> (int * string) list

“主要”只是列表的开头,我选择哪个作为“主要”并不重要,因为我只关心是否所有具有相同位置的字段也具有相同的名称。

这就是为什么我按位置分组,然后减少到一个不同的名称列表,然后只计算条目(>1 显然意味着一些分歧)。


最终解决方案

这就是我最终得到的结果:

let primary = getFields <| fst x
let allSame = (primary) @ ((tail |> List.map (fun (m,_) -> getFields m)) |> List.collect (fun e -> e))
                |> Seq.sortBy (fun (pos, _) -> pos)
                |> Seq.pairwise
                |> Seq.forall (fun ((_,namex),(_,namey)) -> Seq.forall2 (=) namex namey)
if allSame then
  Some (fst x)
else
  failwith "Some error message here"

【问题讨论】:

  • 在这种情况下,我将只使用System.Collection.Generic.Dictionarys,检查键计数并测试所有键的值是否匹配 - 你的似乎有些奇怪 - 它不应该是 Seq.forall取而代之的是 - 即使您的输入字典的每个键都有多个值(另一个缺失)怎么办?
  • 除此之外 - 对两者进行排序,然后压缩然后比较两个组件中匹配部分的元组似乎也是合理的(O(n log n))
  • 我稍微简化了一些,Seq.exists 出现在实际代码的后面,我测试了不同的键数。

标签: dictionary f# idioms


【解决方案1】:

就像@Carsten 在他的评论中所说,按键排序,然后比较每个 KeyValuePair。另外一个好处是,Seq.forall 是惰性的,并在第一次不匹配时停止评估。

[primary; remaining1; remaining2]
|> Seq.map (Seq.sortBy (fun (KeyValue(k,_)) -> k))
|> Seq.pairwise
|> Seq.forall (fun (x, y) -> Seq.forall2 (=) x y)

【讨论】:

  • +1 并被接受,这使我找到了问题的解决方案,需要进行一些调整,因为我没有使用键值,而是使用元组,但最终通过一些元组理解到达了那里。跨度>
【解决方案2】:

为了纯粹的可读性,我更喜欢定义一个辅助函数来测试每个键/值对。

您的问题并未说明不匹配的密钥是否正常,因此请选择合适的:

(不匹配的密钥是可以的)

let looselyAllSame (primary :: remaining) = 
     let hasDifferentName key value = 
          primary |> Map.tryFind key |> Option.exists ((<>) value) 
     not (remaining |> List.exists (Map.exists hasDifferentName))

(不匹配的键是不行的)

let strictlyAllSame (primary :: remaining)= 
     let hasSameName key value = 
          primary |> Map.tryFind key |> Option.exists ((=) value) 
     remaining |> List.forall (Map.forall hasSameName)

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2018-06-04
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-05-15
    • 1970-01-01
    • 2017-04-26
    相关资源
    最近更新 更多