![](/img/trans.png)
[英]Python 3 how to get value from dictionary containing only one key-value pair with unknown key?
[英]How does one get the first key,value pair from F# Map without knowing the key?
如何在不知道鍵的情況下從 F# Map獲取第一個key,value pair
?
我知道 Map 類型用於獲取給定鍵的相應值,例如find 。
我也知道可以將地圖轉換為列表並使用 List.Head,例如
List.head (Map.toList map)
我想這樣做
1.沒有鑰匙
2.不知道key和value的類型
3.不使用可變的
4.無需遍歷整個地圖
5. 不做轉換,遍歷可見后面的整個地圖,例如 Map.toList 等。
我也知道如果一個人得到第一個key,value pair
它可能沒有用,因為地圖文檔沒有說明在兩個不同的調用中使用 map 是否保證相同的順序。
如果無法編寫代碼,則可以接受來自諸如 MSDN 之類的站點的現有參考資料,用於解釋和說明原因。
TLDR;
我如何解決這個問題是轉換這個函數:
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)
它基於列表,用於在string * int
的關聯列表中查找最小值。
示例列表:
["+",10; "-",10; "*",20; "/",20]
該列表用於解析具有優先級的二元運算符表達式,其中字符串是二元運算符,而 int 是優先級。 其他函數是在數據上執行的,因此使用 F# 映射可能比列表更具優勢。 我還沒有決定最終的解決方案,但想在地圖仍然處於最前沿的時候探索這個問題。
目前我正在使用:
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)
但是在這里我不得不在初始狀態("",1000)
進行硬編碼,而最好的方法是使用地圖中的第一個值作為初始狀態,然后將地圖的其余部分作為起始地圖進行傳遞與列表:
(List.tail l) (List.head l)
是的,這是對地圖進行分區,但這不起作用,例如,
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
這導致
val rest : Map<string,int> = map [("*", 20); ("+", 10); ("-", 10)]
val first : Map<string,int> = map [("/", 20)]
首先是兩個映射而不是鍵值對
("/",20)
對於優先解析的實際目的,在最終轉換中查看+
操作之前-
是可取的,因此返回+
之前-
是可取的。 因此, marklam對答案的這種變化
let findmin (map : Map<_,_>) = map |> Seq.minBy (fun kvp -> kvp.Value)
實現了這一點,並通過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
Seq.head
的使用確實返回map
的第一項,但必須注意map
是使用排序的鍵構建的,因此對於我的實際示例,我想從最低值10
,因為這些項是key
排序,返回的第一個是("*",20)
, *
是第一個鍵,因為鍵是字符串並按此類排序。
為了讓我實際使用marklam的答案,我必須在調用之前檢查空列表,然后使用let (a,b) = kvp.Key,kvp.Value
將KeyValuePair的輸出按摩到元組中
我認為沒有完全滿足您所有要求的答案,但是:
您可以使用m |> Seq.head
訪問第一個鍵值對。 與將地圖轉換為列表不同,這很懶惰。 這並不能保證你總是得到相同的第一個元素,但實際上,實現將保證(盡管它可能會在下一個版本中改變)。
為了找到最小值,您實際上並不需要保證Seq.head
始終返回相同的元素。 它只需要給你一些元素。
您可以使用其他基於Seq
的函數作為@marklam 在他的回答中提到的。
您還可以將fold
與option<'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)
它甚至比其他答案更簡單。 Map
內部使用 AVL 平衡樹,因此條目已經按鍵排序。 正如@marklam Map
所提到的,實現了IEnumerable<KeyValuePair<_,_>>
所以:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Seq.head
// will return ("X", 1)
元素添加到映射中的順序無關緊要, Seq.head
可以直接對映射進行操作並返回最小鍵的鍵/值映射。
有時需要將 Map 顯式轉換為 Seq:
let m = Map.empty.Add("Y", 2).Add("X", 1)
let (key, value) = m |> Map.toSeq |> Seq.head
我在這種情況下看到的錯誤消息說“類型'a * 'b
與類型Collections.Generic.KeyValuePair<string, int>
不匹配”。 也可以添加類型注釋而不是Map.toSeq
。
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.