Question

I have a NameValueCollection which I need to convert to a Map and I just can't work it out. I tried:

let headerMap (m : MailMessage) = m.Headers |> Map.map (fun k v -> v.[k])

Do I need to use Seq.map instead?

Basically the point of this is that I want to serialize the headers in a System.Net.MailMessage to JSON.

Was it helpful?

Solution

Daniel's answer will work just fine, but I thought I'd offer some additional alternatives:

Array.fold -- This should be faster than Daniel's version since it avoids the overhead of the iterators.

let mapOfNameValueCollection (collection : NameValueCollection) =
    (Map.empty, collection.AllKeys)
    ||> Array.fold (fun map key ->
        let value = collection.[key]
        Map.add key value map)

Array.fold with sets of values -- Similar to the code above, but returns the value as a Set<string> which may be useful if you want to determine if some value is in the returned set of values.

let mapOfNameValueCollection (collection : NameValueCollection) =
    (Map.empty, collection.AllKeys)
    ||> Array.fold (fun map key ->
        let valueSet =
            match collection.[key] with
            | null ->
                Set.empty
            | values ->
                Set.ofArray <| values.Split [| ',' |]
        Map.add key valueSet map)

Recursive loop -- Creates the map item-by-item with a recursive loop. I wouldn't use this in practice because the Array.fold version would be easier and faster. However, this approach could be faster if the specific collection class you're using (derived from NameValueCollection) overrides the AllKeys property and has some weird internal behavior which takes a long time to return the property value.

let mapOfNameValueCollection (collection : NameValueCollection) =
    let rec createMap map idx =
        if idx < 0 then map
        else
            let itemName = collection.GetKey idx
            let itemValue = collection.[itemName]
            let map = Map.add itemName itemValue map
            createMap map (idx - 1)

    createMap Map.empty (collection.Count - 1)

Imperative loop -- Creates the map item-by-item with an imperative loop. As with the recursive loop, I'd prefer to use Array.fold in practice unless there was some special reason not to.

let mapOfNameValueCollection (collection : NameValueCollection) =
    let mutable map = Map.empty

    let maxIndex = collection.Count - 1
    for i = 0 to maxIndex do
        let itemName = collection.GetKey i
        let itemValue = collection.[itemName]
        map <- Map.add itemName itemValue map

    map

OTHER TIPS

nvc.AllKeys
|> Seq.map (fun key -> key, nvc.[key])
|> Map.ofSeq
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top