Domanda

Google offre molti esempi di aggiunta ed eliminazione di voci in un dizionario F # (o altra raccolta). Ma non vedo esempi all'equivalente di

myDict["Key"] = MyValue;

Ho provato

myDict.["Key"] <- MyValue

Ho anche tentato di dichiarare il dizionario come

Dictionary<string, mutable string>

e diverse varianti su questo. Tuttavia, non ho ancora raggiunto la combinazione corretta ... se è effettivamente possibile in F #.

Modifica: il codice offensivo è:

type Config(?fileName : string) =
    let fileName = defaultArg fileName @"C:\path\myConfigs.ini"

    static let settings =
        dict[ "Setting1", "1";
              "Setting2", "2";
              "Debug",    "0";
              "State",    "Disarray";]

    let settingRegex = new Regex(@"\s*(?<key>([^;#=]*[^;#= ]))\s*=\s*(?<value>([^;#]*[^;# ]))")

    do  File.ReadAllLines(fileName)
        |> Seq.map(fun line -> settingRegex.Match(line))
        |> Seq.filter(fun mtch -> mtch.Success)
        |> Seq.iter(fun mtch -> settings.[mtch.Groups.Item("key").Value] <- mtch.Groups.Item("value").Value)

L'errore che sto ricevendo è:

System.NotSupportedException: This value may not be mutated
   at Microsoft.FSharp.Core.ExtraTopLevelOperators.dict@37-2.set_Item(K key, V value)
   at <StartupCode$FSI_0036>.$FSI_0036_Config.$ctor@25-6.Invoke(Match mtch)
   at Microsoft.FSharp.Collections.SeqModule.iter[T](FastFunc`2 action, IEnumerable`1 sequence)
   at FSI_0036.Utilities.Config..ctor(Option`1 fileName)
   at <StartupCode$FSI_0041>.$FSI_0041.main@()
stopped due to error
È stato utile?

Soluzione

f # ha due strutture dati associative comuni:

Quello a cui sei più abituato, il Dizionario mutabile che eredita che è alla sua presenza nel BCL e usa una tabella hash sotto il cofano.

let dict = new System.Collections.Generic.Dictionary<string,int>()
dict.["everything"] <- 42

L'altro è noto come Mappa ed è, nello stile funzionale comune, immutabile e implementato con alberi binari.

Invece di operazioni che potrebbero cambiare un dizionario, le mappe forniscono operazioni che restituiscono una nuova mappa che è il risultato di qualsiasi modifica sia stata richiesta. In molti casi, sotto il cofano non è necessario creare una copia completamente nuova dell'intera mappa, quindi lo sono quelle parti che possono essere condivise normalmente. Ad esempio:

let withDouglasAdams = Map.add "everything" 42 Map.empty

Il valore withDouglasAdams rimarrà per sempre come associazione di " tutto " a 42. quindi se in seguito lo fai:

let soLong = Map.remove "everything" withDouglasAdams

Quindi l'effetto di questa 'rimozione' è visibile solo tramite il soLong valore.

La mappa di F # è, come detto, implementata come un albero binario. La ricerca è quindi O (log n) mentre un dizionario (ben educato) dovrebbe essere O (1). In pratica un dizionario basato sull'hash tenderà a sovraperformare quello basato sull'albero in quasi tutti i semplici (basso numero di elementi, bassa probabilità di collisione) in quanto tale è comunemente usato. Detto questo, l'aspetto immutabile della mappa può consentire di usarlo in situazioni in cui il dizionario richiederebbe invece un blocco più complesso o di scrivere un codice più "elegante" con meno effetti collaterali e quindi rimane un'alternativa utile.

Questa non è tuttavia la fonte del tuo problema. L'operatore 'dict restituisce un'implementazione IDictionary<K,T> immutabile esplicitamente (nonostante non lo indichi nella sua documentazione).

Da fslib-extra-pervasives.fs (nota anche l'uso delle opzioni sui tasti):

let dict l = 
    // Use a dictionary (this requires hashing and equality on the key type)
    // Wrap keys in an Some(_) option in case they are null 
    // (when System.Collections.Generic.Dictionary fails). Sad but true.
    let t = new Dictionary<Option<_>,_>(HashIdentity.Structural)
    for (k,v) in l do 
        t.[Some(k)] <- v
    let d = (t :> IDictionary<_,_>)
    let c = (t :> ICollection<_>)
    let ieg = (t :> IEnumerable<_>)
    let ie = (t :> System.Collections.IEnumerable)
    // Give a read-only view of the dictionary
    { new IDictionary<'key, 'a> with 
            member s.Item 
                with get x = d.[Some(x)]            
                and  set (x,v) = raise (NotSupportedException(
                                            "This value may not be mutated"))
   ...

Altri suggerimenti

Che errore ricevi? Ho provato quanto segue e si compila bene

let map = new System.Collections.Generic.Dictionary<string,int>()
map.["foo"] <- 42

MODIFICA Verifica che anche questo codice funzioni correttamente.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top