Извлечение значения данных первичного ключа из последовательности словарей

#f# #dictionary #set #sequence

#f# #словарь #установить #последовательность

Вопрос:

Я написал следующий код, чтобы извлечь значения полей ID из последовательности словарей и вернуть их в виде набора — в основном я ищу значения PK для строк в таблице db, которую я использовал для заполнения словаря (1 dict на строку таблицы). Ниже кода приведены некоторые примеры данных, которые загружаются в последовательности словаря.

Хотя приведенный ниже код работает, стиль, вероятно, мог бы быть более функциональным — мне пришлось прибегнуть к использованию изменяемого списка для построения результирующего набора. Так что мне это кажется неправильным.

Кто-нибудь хочет предложить улучшенное, более функциональное решение здесь.

 // Extract the PK values from a dictionary and create a key set  from these data values
// The expected result here is: set ["PK1"; "PK2"; "PK3"; "PK4"]
let get_keyset (tseq:seq<Dictionary<string,string>>) =  
    let mutable setres =[]  
    for x in tseq do  
        for KeyValue(k,v) in x do  
            // Extract ID values/keys from each dict  
            setres <- x.Item("ID")::setres  
    setres |> List.rev |> Set.ofList   

// Sample Data  
// First Tuple is PK/ID value  
let tabledata = [  
                [("ID", "PK1"); ("a2","aa"); ("a3", "aaa"); ("a4", "aaaa") ]  
                [("ID", "PK2"); ("b2","bb"); ("b3", "bbb"); ("b4", "bbbb") ]  
                [("ID", "PK3"); ("c2","cc"); ("c3", "ccc"); ("c4", "cccc") ]  
                [("ID", "PK4"); ("d2","dd"); ("d3", "ddd"); ("d4", "dddd") ]  
                ]  

//generate dict sequence from datasets  
let gendictseq tabledata =  
    seq {  
        for tl in tabledata do  
            let ddict = new Dictionary<string,string>()    
            for (k,v) in tl do  
                    ddict.Add(k,v)  
            yield ddict  
    }  
  

Комментарии:

1. Если вы используете Set.ofList, зачем вам нужно перевернуть список?

Ответ №1:

Ваш get_keyset выглядит довольно запутанным для меня. Это значительно более сжато:

 let get_keyset tseq =
    tseq |> Seq.map (fun (x:Dictionary<_,_>) -> x.["ID"]) |> set
  

Для gendictseq я бы лично предпочел функции более высокого порядка выражению последовательности, но это в значительной степени вопрос вкуса:

 let gendictseq tabledata =
    tabledata
    |> Seq.map (fun table ->
        (Dictionary<_,_>(), table)
        ||> List.fold (fun dict keyValue -> dict.Add keyValue; dict))
  

Комментарии:

1. Согласен на повторную свертку в моем коде — вот почему я опубликовал. Ваши решения иллюстрируют реальную мощь подхода fp, где код действительно может быть сведен всего к нескольким кратким выражениям. (Я все еще изучаю этот материал — ваши примеры действительно помогают — Спасибо).

2. @BrendanC : get_keyset Можно было бы написать еще один интересный способ: let get_keyset : Dictionary<_,string> seq -> Set<_> = Seq.map (fun x -> x.["ID"]) >> set :-]

Ответ №2:

Использование ResizeArray ( List<T> в C #) лучше, чем изменяемая переменная списка:

 let getKeyset (tseq:seq<Dictionary<string,string>>) =  
    let setres = new ResizeArray<string>()
    for x in tseq do 
        for KeyValue(k,v) in x do 
            setres.Add(x.["ID"])
    setres |> Set.ofSeq
  

или используйте более функциональное вычисление последовательности:

 let getKeyset2 (tseq:seq<Dictionary<string,string>>) =  
    seq {
        for x in tseq do 
            for KeyValue(k,v) in x do 
                yield x.["ID"]
        }
    |> Set.ofSeq
  

Комментарии:

1. Я бы сказал, что выражения последовательности менее функциональны и более обязательны…

Ответ №3:

Функционально эта операция представляет собой отображение, как показано ниже:

 let get_keyset_new (tseq:seq<Dictionary<string,string>>) = 
  let s = tseq |> Seq.map (fun i -> i |> Seq.map (fun e -> i.Item("ID") ) )
  seq {
      for i in s do
          yield! i
  } |> Set.ofSeq