2016-03-08 23 views
5

Questa domanda viene da qualcuno che sta lavorando per eseguire la transizione da R a F #. Riconosco pienamente il mio approccio qui potrebbe essere sbagliato, quindi sto cercando il modo F # di farlo. Ho una situazione in cui voglio eseguire una iterazione attraverso un insieme di file XML, analizzarli ed estrapolare diversi valori per identificare quelli che necessitano di ulteriore elaborazione. La mia naturale inclinazione è di mappare l'array di dati XML, exampleData in questo caso, analizzare ciascuno utilizzando il provider di tipo RawDataProvider e infine creare un oggetto Map per ogni file contenente l'XML analizzato, il valore Status dall'XML e l'ItemId valore.Tipo di raccolta F # per tipi misti

Si scopre che il tipo di mappa in F # non è come un elenco in R. Le liste in R sono essenzialmente hashmap che possono supportare tipi misti. Sembra che il tipo di mappa in F # non supporti la memorizzazione di tipi misti. Ho trovato che questo è incredibilmente utile nel mio lavoro su R e sto cercando quale sia la raccolta F # giusta per questo.

Oppure, sto pensando a tutto questo? Questo è un modo molto naturale per me di elaborare i dati in R quindi mi aspetto che ci sia un modo per farlo anche in F #. L'assunto è che ho intenzione di fare ulteriori analisi e aggiungere ulteriori elementi di dati a queste raccolte.

Aggiornamento: Questo mi sembra un così semplice caso d'uso che ci deve essere un modo idiomatico di fare questo in F #, senza dover definire un tipo di record per ogni fase dell'analisi. Ho aggiornato il mio esempio per illustrare ulteriormente cosa sto cercando di fare. Voglio tornare un array degli oggetti mappa che ho analizzato:

type RawDataProvider = XmlProvider<"""<product Status="Good" ItemId="123" />""">   

let exampleData = [| """<product Status="Good" ItemId="123" />"""; """<product Status="Bad" ItemId="456" />"""; """<product Status="Good" ItemId="789" />"""|] 

let dataResult = 
      exampleData 
      |> Array.map(fun fileData -> RawDataProvider.Parse(fileData)) 
      |> Array.map(fun xml -> Map.empty.Add("xml", xml).Add("Status", xml.Status).Add("ItemId", xml.ItemId)) 
      |> Array.map(fun elem -> elem.["calc1Value"] = calc1 elem["itemId"]) 
      |> Array.map(fun elem -> elem.["calc2"] = calc2 elem.["ItemId"] elem.["calc1Value"]) 
+0

Non è quello che hai chiesto, ma penso che 'File.ReadAllLines (file) |> Array.reduce (+)' potrebbe essere sostituito con 'File.ReadAllText (file)' – CoderDennis

+0

@CoderDennis grazie per le informazioni –

+0

usa un tipo di record invece dell'hash vagamente digitato. –

risposta

4

Questo è quello che io considero quasi idiomatica qui - Sto mantenendo la stessa forma nel tuo esempio in modo da poter abbinare i due:

let dataResult = 
    exampleData 
    |> Array.map(fun fileData -> RawDataProvider.Parse(fileData)) 
    |> Array.map(fun xml -> xml, calc1 xml.ItemId) 
    |> Array.map(fun (xml, calcedValue1) -> xml, calcedValue1, calc2 xml.ItemId calcedValue1) 

Cosa XmlProvider dà veramente non è semplicemente xml parsing, ma il fatto che esso genera una rappresentazione fortemente tipizzato del xml. Questo è meglio che inserire i dati in una mappa, in quanto ti dà maggiori garanzie sul fatto che il tuo programma stia facendo la cosa giusta. Ad esempio non ti consente di mischiare itemId e ItemId come è successo nel tuo snippet di codice;)

Per i valori che calcoli nei passaggi seguenti, potresti usare tuple invece di un record. In generale, i record sono preferiti alle tuple in quanto portano a un codice più leggibile, ma combinare i valori correlati di tipi diversi in aggregati ad-hoc è in realtà lo scenario in cui l'uso delle tuple brilla.

Ora, ho detto quasi idiomatica - vorrei rompere l'analisi e XMLs elaborazione analizzato in funzioni distinte, e calcolare sia calc1 e calc2 risultati in una singola funzione, invece di comporre due Array.maps come questo:

let dataResult = 
    parsedData 
    |> Array.map(fun xml -> 
     let calced1 = calc1 xml.ItemId 
     xml, calced1, calc2 xml.ItemId calced1) 

Se provieni da sfondo R, potresti dare un'occhiata a Deedle per un approccio alternativo. Ti dà un flusso di lavoro simile a R in F #.