2009-07-29 3 views
11

Google donne beaucoup d'exemples d'ajout et de suppression d'entrées dans un dictionnaire F # (ou autre collection). Mais je ne vois pas d'exemples à l'équivalent deComment déclarez-vous les valeurs d'une entrée de dictionnaire comme mutable?

myDict["Key"] = MyValue; 

J'ai essayé

myDict.["Key"] <- MyValue 

J'ai aussi tenté de déclarer le dictionnaire comme

Dictionary<string, mutable string> 

ainsi plusieurs variantes sur ce. Cependant, je n'ai pas encore atteint la bonne combinaison ... si est réellement possible en F #.

Edit: Le code incriminé est:

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'erreur que je reçois est:

System.NotSupportedException: This value may not be mutated 
    at [email protected]_Item(K key, V value) 
    at <StartupCode$FSI_0036>[email protected](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>[email protected]() 
stopped due to error 

Répondre

24

f # a deux structures de données associatives communes:

celui que vous le plus utilisé pour le mutable Dictionnaire dont elle hérite qui est de sa présence dans la BCL et utilise une table de hachage sous le capot.

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

L'autre est connu comme Map et est, dans un style fonctionnel commun, immuable et mis en œuvre avec des arbres binaires. Au lieu des opérations qui pourraient modifier un dictionnaire, les cartes fournissent des opérations qui renvoient une nouvelle carte qui est le résultat de tout changement demandé. Dans de nombreux cas, sous le capot, il n'est pas nécessaire de faire une copie entièrement nouvelle de la carte entière, donc les parties qui peuvent être partagées normalement le sont. Par exemple:

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

La valeur withDouglasAdams restera à jamais comme une association de « tout » à 42. Donc, si vous faites plus tard:

let soLong = Map.remove "everything" withDouglasAdams 

Puis l'effet de cette « suppression » est visible que via la valeur .

La carte de F # est, comme mentionné, implémentée comme un arbre binaire. La recherche est donc O (log n) alors qu'un dictionnaire (bien comporté) devrait être O (1). Dans la pratique, un dictionnaire basé sur le hachage aura tendance à surpasser celui basé sur l'arbre dans presque tous les simples (faible nombre d'éléments, faible probabilité de collision) en tant que tel est couramment utilisé. Cela dit, l'aspect immuable de la carte peut vous permettre de l'utiliser dans des situations où le dictionnaire aurait plutôt besoin d'un verrouillage plus complexe ou d'écrire un code plus «élégant» avec moins d'effets secondaires et donc cela reste une alternative utile.

Ceci n'est cependant pas la source de votre problème.L'opérateur 'dict' renvoie une implémentation explicitement immutable IDictionary<K,T> (bien que cela ne soit pas indiqué dans sa documentation).

De fslib-extra-pervasives.fs (note également l'utilisation d'options sur les touches):

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")) 
    ... 
+0

le temps de disponibilité des sites de recherche est vraiment plutôt pauvre. Voici le lien google cache temporairement http://209.85.229.132/search?q=cache:GGIlRD9kBnYJ:research.microsoft.com/en-us/um/cambridge/projects/fsharp/manual/fsharp.core/microsoft.fsharp. collections.map.html + f% 23 + microsoft.fsharp.collections.map & cd = 1 & hl = fr & ct = clnk & gl = fr – ShuggyCoUk

+3

Notez que la recherche dans une arborescence binaire est O (log n), pas O (n log n) comme indiqué. – kvb

+0

oops - faute de frappe – ShuggyCoUk

5

Quelle est l'erreur que vous obtenez? J'ai essayé ce qui suit et il compile très bien

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

EDIT Vérifiez que ce code a couru très bien aussi.

+0

Intéressant ... Je viens de carte [ "foo"] <-. 42 ;; carte. ["Foo"] <- 43 ;; OK – telesphore4

+0

Peut-être que c'est quelque chose d'autre ... Je supprimerais le poste, mais je ne peux pas – telesphore4

Questions connexes