简体   繁体   English

如何在不知道键的情况下从 F# Map 获取第一个键值对?

[英]How does one get the first key,value pair from F# Map without knowing the key?

How does one get the first key,value pair from F# Map without knowing the key?如何在不知道键的情况下从 F# Map获取第一个key,value pair

I know that the Map type is used to get a corresponding value given a key, eg find .我知道 Map 类型用于获取给定键的相应值,例如find

I also know that one can convert the map to a list and use List.Head, eg我也知道可以将地图转换为列表并使用 List.Head,例如

List.head (Map.toList map)

I would like to do this我想这样做
1. without a key 1.没有钥匙
2. without knowing the types of the key and value 2.不知道key和value的类型
3. without using a mutable 3.不使用可变的
4. without iterating through the entire map 4.无需遍历整个地图
5. without doing a conversion that iterates through the entire map behind the seen, eg Map.toList, etc. 5. 不做转换,遍历可见后面的整个地图,例如 Map.toList 等。

I am also aware that if one gets the first key,value pair it might not be of use because the map documentation does not note if using map in two different calls guarantees the same order.我也知道如果一个人得到第一个key,value pair它可能没有用,因为地图文档没有说明在两个不同的调用中使用 map 是否保证相同的顺序。

If the code can not be written then an existing reference from a site such as MSDN explaining and showing why not would be accepted.如果无法编写代码,则可以接受来自诸如 MSDN 之类的站点的现有参考资料,用于解释和说明原因。

TLDR; TLDR;

How I arrived at this problem was converting this function:我如何解决这个问题是转换这个函数:

let findmin l = 
    List.foldBack
        (fun (_,pr1 as p1) (_,pr2 as p2) -> if pr1 <= pr2 then p1 else p2)
        (List.tail l) (List.head l)

which is based on list and is used to find the minimum value in the associative list of string * int .它基于列表,用于在string * int的关联列表中查找最小值。

An example list:示例列表:

["+",10; "-",10; "*",20; "/",20]

The list is used for parsing binary operator expressions that have precedence where the string is the binary operator and the int is the precedence.该列表用于解析具有优先级的二元运算符表达式,其中字符串是二元运算符,而 int 是优先级。 Other functions are preformed on the data such that using F# map might be an advantage over list.其他函数是在数据上执行的,因此使用 F# 映射可能比列表更具优势。 I have not decided on a final solution but wanted to explore this problem with map while it was still in the forefront.我还没有决定最终的解决方案,但想在地图仍然处于最前沿的时候探索这个问题。

Currently I am using:目前我正在使用:

let findmin m =
    if Map.isEmpty m then 
        None
    else
        let result = 
            Map.foldBack 
                (fun key value (k,v) -> 
                    if value <= v then (key,value) 
                    else (k,v))
                m ("",1000)
        Some(result)

but here I had to hard code in the initial state ("",1000) when what would be better is just using the first value in the map as the initial state and then passing the remainder of the map as the starting map as was done with the list:但是在这里我不得不在初始状态("",1000)进行硬编码,而最好的方法是使用地图中的第一个值作为初始状态,然后将地图的其余部分作为起始地图进行传递与列表:

(List.tail l) (List.head l)

Yes this is partitioning the map but that did not work eg,是的,这是对地图进行分区,但这不起作用,例如,

let infixes = ["+",10; "-",10; "*",20; "/",20]
let infixMap = infixes |> Map.ofList
let mutable test = true
let fx k v : bool =
    if test then 
        printfn "first"
        test <- false
        true
    else 
        printfn "rest"
        false
let (first,rest) = Map.partition fx infixMap

which results in这导致

val rest : Map<string,int> = map [("*", 20); ("+", 10); ("-", 10)]  
val first : Map<string,int> = map [("/", 20)]

which are two maps and not a key,value pair for first首先是两个映射而不是键值对

("/",20)

Notes about answers关于答案的注释

For practical purposes with regards to the precedence parsing seeing the + operations before - in the final transformation is preferable so returning + before - is desirable.对于优先解析的实际目的,在最终转换中查看+操作之前-是可取的,因此返回+之前-是可取的。 Thus this variation of the answer by marklam因此, marklam对答案的这种变化

let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Value)

achieves this and does this variation by Tomas实现了这一点,并通过Tomas 进行了这种变化

let findmin m = 
    Map.foldBack (fun k2 v2 st ->
        match st with
        | Some(k1, v1) when v1 < v2 -> st
        | _ -> Some(k2, v2)) m None

The use of Seq.head does return the first item in the map but one must be aware that the map is constructed with the keys sorted so while for my practical example I would like to start with the lowest value being 10 and since the items are sorted by key the first one returned is ("*",20) with * being the first key because the keys are strings and sorted by such. Seq.head的使用确实返回map的第一项,但必须注意map是使用排序的键构建的,因此对于我的实际示例,我想从最低值10 ,因为这些项是key排序,返回的第一个是("*",20)*是第一个键,因为键是字符串并按此类排序。

For me to practically use the answer by marklam I had to check for an empty list before calling and massage the output from a KeyValuePair into a tuple using let (a,b) = kvp.Key,kvp.Value为了让我实际使用marklam的答案,我必须在调用之前检查空列表,然后使用let (a,b) = kvp.Key,kvp.ValueKeyValuePair的输出按摩到元组中

I don't think there is an answer that fully satisfies all your requirements, but:我认为没有完全满足您所有要求的答案,但是:

  1. You can just access the first key-value pair using m |> Seq.head .您可以使用m |> Seq.head访问第一个键值对。 This is lazy unlike converting the map to list.与将地图转换为列表不同,这很懒惰。 This does not guarantee that you always get the same first element, but realistically, the implementation will guarantee that (it might change in the next version though).这并不能保证你总是得到相同的第一个元素,但实际上,实现将保证(尽管它可能会在下一个版本中改变)。

  2. For finding the minimum, you do not actually need the guarantee that Seq.head returns the same element always.为了找到最小值,您实际上并不需要保证Seq.head始终返回相同的元素。 It just needs to give you some element.它只需要给你一些元素。

  3. You can use other Seq -based functons as @marklam mentioned in his answer.您可以使用其他基于Seq的函数作为@marklam 在他的回答中提到的。

  4. You can also use fold with state of type option<'K * 'V> , which you can initialize with None and then you do not have to worry about finding the first element:您还可以将foldoption<'K * 'V>类型的状态一起使用,您可以使用None进行初始化,然后您不必担心找到第一个元素:

     m |> Map.fold (fun st k2 v2 -> match st with | Some(k1, v1) when v1 < v2 -> st | _ -> Some(k2, v2)) None

Map实现了IEnumerable<KeyValuePair<_,_>>所以你可以把它当作一个Seq ,比如:

let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Key)

It's even simpler than the other answers.它甚至比其他答案更简单。 Map internally uses an AVL balanced tree so the entries are already ordered by key. Map内部使用 AVL 平衡树,因此条目已经按键排序。 As mentioned by @marklam Map implements IEnumerable<KeyValuePair<_,_>> so:正如@marklam Map所提到的,实现了IEnumerable<KeyValuePair<_,_>>所以:

let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Seq.head
// will return ("X", 1)

It doesn't matter what order the elements were added to the map, Seq.head can operate on the map directly and return the key/value mapping for the min key.元素添加到映射中的顺序无关紧要, Seq.head可以直接对映射进行操作并返回最小键的键/值映射。

Sometimes it's required to explicitly convert Map to Seq:有时需要将 Map 显式转换为 Seq:

let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Map.toSeq |> Seq.head

The error message I've seen for this case says "the type 'a * 'b does not match the type Collections.Generic.KeyValuePair<string, int> ".我在这种情况下看到的错误消息说“类型'a * 'b与类型Collections.Generic.KeyValuePair<string, int>不匹配”。 It may also be possible add type annotations rather than Map.toSeq .也可以添加类型注释而不是Map.toSeq

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

相关问题 Python 3 如何从只包含一个未知键的键值对的字典中获取值? - Python 3 how to get value from dictionary containing only one key-value pair with unknown key? 字典在不知道键的情况下获取值 - Dictionary get value without knowing the key 有没有办法从地图上获取特定的键值对? - Is there a way to get a specific key-value pair from the map? 如何从 dart flutter 中的键或键值对获取索引 - How to get index from key or key value pair in dart flutter 如何添加一对整数列表作为 Map 中的值,其中键作为对中的第一个值 - Java - How to add a List of a pair of integers as a value in a Map with key as first value in the pair - Java 如何获取 Map object 中唯一的键值对? - How to get the only key-value pair in a Map object? 如何从列表中删除键/值对<Map<String, Object> &gt; - How to remove the key/value pair from a List<Map<String, Object>> 在不知道密钥的情况下获取std :: map中的值类型 - Getting the type of a value in std::map without knowing the key 如何在不知道Clojure中的键的情况下将地图构造成键值对? - How do you destructure a map into key-value pairs without knowing the keys in Clojure? 从 Map 获取密钥<string,list<string> &gt; 知道列表值之一</string,list<string> - get key from Map<String,List<String>> knowing one of the List values
 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM