2009-03-06 13 views
2

Ich habe eine HashTable, die ich verfolgen Farben (die die Schlüssel sind) und Anzahl der Farben, die der Schlüssel ist.Wie kann ich den Wert in einer HashTable erhöhen?

Ich versuche herauszufinden, wie der Schlüssel erhöht wird, wenn es die HashTable bereits die Farbe enthält. Hier ist ein Code-Schnipsel:

Hashtable htColors = new Hashtable(); 

if (htColors.Contains(color)) 
{ 
    // Want to increase the "value" of the key here.  
} 
else 
{ 
    htColors.Add(color, 1); //Found color for first time 
} 

Antwort

4

Versuchen Sie, die folgenden

if (htColors.Contains(color)) 
{ 
    int old = (int)htColors[color]; 
    htColor[color] = old + 1; 
} 

EDIT Antwort auf Kommentare

IMHO, das Wörterbuch Ansatz ist viel besser, weil es 1) Typ Safe und 2) beseitigt das Boxen in dieser Lösung beteiligt.

Mit der Linie sein, die folgenden werden die Schlüssel nicht beeinflussen, nur den Wert

htColor[color] = (int)htColor[color] + 1; 
+0

Ok, Ihre Lösung scheint zu funktionieren. Was denkst du über die Wörterbuchalternative? Was passiert, wenn ich nur (int) htColors [color] + 1, würde das den Schlüssel oder Wert ändern? – Xaisoft

+0

Danke für die Hilfe mit der HashTable. Es sieht so aus, als würde ich doch mit einem Wörterbuch gehen. – Xaisoft

+0

Jemand kann mich korrigieren, wenn ich hier falsch liege, aber ich glaube, das automatische Boxen/Unboxing tritt für jeden Werttyp auf, der in den Heap verschoben wird, sogar (in diesem Fall) ints in einem typisierten Wörterbuch (Dictionary ). Was Wörterbuch eliminiert, ist Unordnung vom Casting. –

4

ich das bin Entsendung pedantisch zu sein. Ich mag die Anbindung an Dictionary nicht, da diese sehr häufige Art von Zugriff kostenintensiv ist - wenn Ihr häufigster Fall ein bereits existierendes Element berührt, müssen Sie den Hashwert dreimal nachschlagen. Glaub mir nicht? Ich schrieb DK-Lösung hier:

static void AddInc(Dictionary<string, int> dict, string s) 
{ 
    if (dict.ContainsKey(s)) 
    { 
     dict[s]++; 
    } 
    else 
    { 
     dict.Add(s, 1); 
    } 
} 

Wenn in IL setzen - Sie diese:

L_0000: nop 
L_0001: ldarg.0 
L_0002: ldarg.1 
L_0003: callvirt instance bool [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::ContainsKey(!0) 
L_0008: ldc.i4.0 
L_0009: ceq 
L_000b: stloc.0 
L_000c: ldloc.0 
L_000d: brtrue.s L_0028 
L_000f: nop 
L_0010: ldarg.0 
L_0011: dup 
L_0012: stloc.1 
L_0013: ldarg.1 
L_0014: dup 
L_0015: stloc.2 
L_0016: ldloc.1 
L_0017: ldloc.2 
L_0018: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::get_Item(!0) 
L_001d: ldc.i4.1 
L_001e: add 
L_001f: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::set_Item(!0, !1) 
L_0024: nop 
L_0025: nop 
L_0026: br.s L_0033 
L_0028: nop 
L_0029: ldarg.0 
L_002a: ldarg.1 
L_002b: ldc.i4.1 
L_002c: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1) 
L_0031: nop 
L_0032: nop 
L_0033: ret 

, die ContainsKey, get_item Anrufe und set_item, von denen alle Hash und nachschlagen.

Ich schrieb etwas weniger hübsch, die eine Klasse verwendet, die ein int enthält und die Klasse können Sie Seite-Wirkung (Sie können nicht wirklich eine Struktur ohne die gleiche Strafe wegen der Struktur kopieren Semantik).

class IntegerHolder { 
    public IntegerHolder(int x) { i = x; } 
    public int i; 
} 
static void AddInc2(Dictionary<string, IntegerHolder> dict, string s) 
{ 
    IntegerHolder holder = dict[s]; 
    if (holder != null) 
    { 
     holder.i++; 
    } 
    else 
    { 
     dict.Add(s, new IntegerHolder(1)); 
    } 
} 

Dies gibt Ihnen die folgende IL:

L_0000: nop 
L_0001: ldarg.0 
L_0002: ldarg.1 
L_0003: callvirt instance !1 [mscorlib]System.Collections.Generic.Dictionary`2<string, class AddableDictionary.IntegerHolder>::get_Item(!0) 
L_0008: stloc.0 
L_0009: ldloc.0 
L_000a: ldnull 
L_000b: ceq 
L_000d: stloc.1 
L_000e: ldloc.1 
L_000f: brtrue.s L_0023 
L_0011: nop 
L_0012: ldloc.0 
L_0013: dup 
L_0014: ldfld int32 AddableDictionary.IntegerHolder::i 
L_0019: ldc.i4.1 
L_001a: add 
L_001b: stfld int32 AddableDictionary.IntegerHolder::i 
L_0020: nop 
L_0021: br.s L_0033 
L_0023: nop 
L_0024: ldarg.0 
L_0025: ldarg.1 
L_0026: ldc.i4.1 
L_0027: newobj instance void AddableDictionary.IntegerHolder::.ctor(int32) 
L_002c: callvirt instance void [mscorlib]System.Collections.Generic.Dictionary`2<string, class AddableDictionary.IntegerHolder>::Add(!0, !1) 
L_0031: nop 
L_0032: nop 
L_0033: ret 

Welche get_item einmal nennt - es gibt keine zusätzlichen Hashing ist im Fall eines Objekts vorhanden. Ich habe ein wenig sleazy und machte das Feld öffentlich, um die Methode zu vermeiden, die Zugriff auf Eigentum verlangt.

Wenn es nach mir ginge, würde ich diese gesamte Funktionalität in seine eigenen Klasse wickeln und die IntegerHolder Klasse aus der Öffentlichkeit verstecken - hier ist eine Kurzversion:

public class CountableItem<T> 
{ 
    private class IntegerHolder 
    { 
     public int i; 
     public IntegerHolder() { i = 1; } 
    } 
    Dictionary<T, IntegerHolder> dict = new Dictionary<T, IntegerHolder>(); 

    public void Add(T key) 
    { 
     IntegerHolder val = dict[key]; 
     if (val != null) 
      val.i++; 
     else 
      dict.Add(key, new IntegerHolder()); 
    } 

    public void Clear() 
    { 
     dict.Clear(); 
    } 

    public int Count(T key) 
    { 
     IntegerHolder val = dict[key]; 
     if (val != null) 
      return val.i; 
     return 0; 
    } 

    // TODO - write the IEnumerable accessor. 
} 
+0

+1 für eine sehr gute IL Einblick.Dies zeigt, warum/bei Verwendung eines Werttyps für Dictionary-Bucket möglicherweise eine schlechte Idee ist. –

Verwandte Themen