F # NameValueCollection для сопоставления

У меня есть NameValueCollection, который мне нужно преобразовать в карту, и я просто не могу с этим справиться. Я пытался:

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

Нужно ли мне вместо этого использовать Seq.map?

По сути, дело в том, что я хочу сериализовать заголовки в System.Net.MailMessage в JSON.


person shmish111    schedule 01.12.2012    source источник
comment
Связанный вопрос: stackoverflow.com/ questions / 13124865 /   -  person Daniel    schedule 01.12.2012
comment
Я задал вопрос в субботу днем ​​и принял его в субботу вечером, это слишком медленно?   -  person shmish111    schedule 02.12.2012


Ответы (1)


Ответ Дэниела будет работать нормально, но я подумал, что предлагаю дополнительные альтернативы:

Array.fold - это должно быть быстрее, чем версия Даниэля, поскольку позволяет избежать накладных расходов на итераторы.

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

Array.fold с наборами значений - аналогично приведенному выше коду, но возвращает значение в виде Set<string>, что может быть полезно, если вы хотите определить, есть ли какое-либо значение в возвращаемом наборе значений.

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)

Рекурсивный цикл. Создает карту элемент за элементом с помощью рекурсивного цикла. Я бы не стал использовать это на практике, потому что версия Array.fold была бы проще и быстрее. Однако этот подход может быть быстрее, если конкретный класс коллекции, который вы используете (производный от NameValueCollection), переопределяет свойство AllKeys и имеет какое-то странное внутреннее поведение, которое требует много времени для возврата значения свойства.

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)

Императивный цикл - создание карты по пунктам с императивным циклом. Как и в случае с рекурсивным циклом, я бы предпочел использовать Array.fold на практике, если только не было особых причин не делать этого.

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
person Jack P.    schedule 01.12.2012
comment
Имейте в виду, что NameValueCollection допускает более одного значения для каждого ключа. Я не знаю, будет ли MailMessage когда-либо использовать его таким образом, но если это так, ни один из этого кода не будет покрывать этот случай. - person Joel Mueller; 01.12.2012
comment
@JoelMuller Все эти случаи обрабатывают несколько значений. Проиндексированное свойство Item NameValueCollection возвращает те же значения, что и метод GetValues(), оно просто возвращает несколько значений в виде строки, разделенной запятыми (CSV). Мой второй случай разбивает строку CSV и создает Set<string> из значений, в то время как другие случаи возвращают строку CSV напрямую (поэтому возвращаемый тип - строка Map ‹, строка›). Свойство Item, вероятно, использует GetValues() внутри, поэтому может быть более эффективным использовать его напрямую вместо Item. - person Jack P.; 02.12.2012
comment
Извините, я пропустил звонок на Split. Лично я предпочитаю избегать дополнительной работы для сборщика мусора, создаваемого массивом - ›join -› string - ›split -› последовательностью массива, и просто вызывать GetValues ​​напрямую. - person Joel Mueller; 03.12.2012