2016-03-23 16 views
5

In un Dictionary<struct,int>: è possibile Aggiungere/Impostare in una chiamata?C# Dizionario Aggiungi/Imposta in una chiamata per motivi di prestazioni

Quindi è possibile fare il codice qui sotto in una sola ricerca per voce?

_KeyToPoints = new Dictionary<Key,int>(); 

foreach (var entry in billionEntries) 
{ 
    int originalValue; 

    // first lookup 
    _KeyToPoints.TryGetValue(entry.Key, out originalValue); 

    // second lookup 
    _KeyToPoints[key] = originalValue + points;  
} 

Questo viene eseguito in un ciclo molto stretto su un'enorme quantità di dati, quindi tutte le prestazioni sono importanti.

Oppure esiste una struttura dati più adatta?

+1

Non credo tu possa evitare di dover indicizzare nel dizionario due volte (una volta per ottenere un valore esistente, e ancora per impostare il valore), ma puoi saltare l'impostazione del valore originale su 0, poiché TryGetValue lo farà per te se la chiave non viene trovata. E, è necessario verificare se TryGetValue restituisce false. – SlimsGhost

+1

Esiste un problema di prestazioni effettive relativo all'intero processo o stai semplicemente dicendo che ce ne sarà uno? Le ricerche del dizionario sono O (1), quindi con il look up (e il set relativo) dovrebbero esserci pochissime prestazioni) –

+0

@SlimsGhost Non è necessario controllare il risultato in questo caso - se la chiave non esistesse, allora '_KeyToPoints [chiave]' memorizzerebbe '0 + punti' in quella posizione chiave. Il codice sarebbe lo stesso sia che la chiave esistesse o meno. –

risposta

2

Sì, c'è un modo per farlo, ma ha uno svantaggio. Considerate questa classe:

class Ref<T> 
{ 
    public T Value; 
} 

è possibile utilizzare un Dictionary<K, Ref<int>> dict e poi fare questo:

Ref<int> count; 
if (!dict.TryGetValue(key, out count)) 
{ 
    count = new Ref<int> { Value = 0 }; 
    dict[key] = count; 
} 
count.Value += points; 

Il rovescio della medaglia è che ora avete un oggetto mucchio aggiuntivo per l'ingresso nel dizionario. A seconda della situazione, questo può o non può essere accettabile.

+0

È davvero più veloce? Stai praticamente eseguendo le stesse operazioni e il primo hit (quando aggiungi un elemento al dizionario) è ancora più pesante a causa della creazione di un oggetto. –

+1

@QualityCatalyst I due approcci dovrebbero essere profilati. La domanda come la interpretavo era semplicemente se fosse possibile farlo con una sola ricerca del dizionario. Ho appena spiegato che, sì, è possibile e qualitativamente caratterizzato il rovescio della medaglia. Può darsi che la profilazione sveli che questo è un approccio orribile per le prestazioni, ma non credo che ciò invalida la risposta. –

+0

Grazie, Timothy ma in questo caso crea problemi molto più grandi :) Immagino di non aver specificato la mia domanda abbastanza bene. Se questo è davvero l'unico modo lo accetterò comunque –

-1

Soluzione molto spiacevole, ma sarà più veloce supponendo che si chiami il metodo AddPoints() principalmente per gli elementi già esistenti nel dizionario.

void AddPoints(T key, int points) 
{ 
    try 
    { 
     _KeyToPoints[key] = _KeyToPoints[key] + points; 
    } 
    catch (ArgumentException) 
    { 
     _KeyToPoints[key] = points; 
    } 
} 

L'eccezione di lancio e gestione è molto costosa (richiede tempo) e avrà un impatto negativo sulle prestazioni. Per evitare ciò, è possibile precompilare il dizionario in questo modo:

void PreFillKeys(params T[] keys) // use an IEnumerable<T> if handier 
{ 
    foreach (T key in keys) 
    { 
     // EITHER THIS: 
     if (!_KeyToPoints.ContainsKey(key)) 
      _KeyToPoints[key] = 0; 
     /* OR THIS (faster if you know none of keys was added before) 
     try 
     { 
      _KeyToPoints[key] = 0; 
     } 
     catch (ArgumentException) 
     { 
      // ignore >> you shouldn't have called 
     } 
     */ 
    } 
} 
0

È possibile utilizzare il vecchio Hashtable contenitore:

Hashtable map = new Hashtable(); 
map[key] = value; 

Se la chiave non esiste, si creerà e aggiungerlo automaticamente alla mappa. Ma soffrirai del boxing/unboxing se usi una chiave di tipo value ...