C# 如何增加哈希表中的值?

C# 如何增加哈希表中的值?,c#,C#,我有一个哈希表,我在跟踪颜色(关键点)和颜色计数(关键点) 我试图找出当哈希表中已经包含颜色时如何增加键。以下是一段代码片段: 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

我有一个哈希表,我在跟踪颜色(关键点)和颜色计数(关键点)

我试图找出当哈希表中已经包含颜色时如何增加键。以下是一段代码片段:

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
}
试试下面的方法

if (htColors.Contains(color))
{
   int old = (int)htColors[color];
   htColor[color] = old + 1;
}
编辑对评论的回复

IMHO,字典方法要好得多,因为它是1)类型安全的,2)消除了此解决方案中涉及的装箱

将行设置为以下值不会影响键,只会影响值

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

我发这篇文章是为了学究。我不喜欢与Dictionary的接口,因为这种非常常见的访问方式是有代价的——如果您最常见的情况是涉及一个已经存在的元素,那么您必须散列并查找您的值3次。不相信我?我在这里写了DK的解决方案:

static void AddInc(Dictionary<string, int> dict, string s)
{
    if (dict.ContainsKey(s))
    {
        dict[s]++;
    }
    else
    {
        dict.Add(s, 1);
    }
}
静态void AddInc(字典dict,字符串s)
{
如果(主旨)
{
dict[s]++;
}
其他的
{
补充条款(第1条);
}
}
当输入IL时,您会得到以下信息:

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
L_0000:nop
L_0001:ldarg.0
L_0002:ldarg.1
L_0003:callvirt实例bool[mscorlib]System.Collections.Generic.Dictionary`2::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_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实例!1[mscorlib]System.Collections.Generic.Dictionary`2::get_项(!0)
L_001d:ldc.i4.1
L_001e:添加
L_001f:callvirt实例void[mscorlib]System.Collections.Generic.Dictionary`2::set_项(!0,!1)
L_0024:没有
L_0025:没有
L_0026:br.s L_0033
L_0028:没有
L_0029:ldarg.0
L_002a:ldarg.1
L_002b:ldc.i4.1
L_002c:callvirt实例无效[mscorlib]System.Collections.Generic.Dictionary`2::Add(!0,!1)
L_0031:没有
L_0032:没有
L_0033:ret
调用ContainsKey、get_item和set_item,所有这些都是散列和查找

我写了一些不那么漂亮的东西,它使用了一个包含int的类,而该类允许您对它产生副作用(由于结构复制语义,您不能真正使用结构而不招致同样的惩罚)

类整数处理器{
公共整数处理器(int x){i=x;}
公共国际一级;
}
静态void AddInc2(字典dict dict,字符串s)
{
整数持有人=dict[s];
if(holder!=null)
{
holder.i++;
}
其他的
{
dict.Add(s,新整数(1));
}
}
这将为您提供以下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 
L_0000:nop
L_0001:ldarg.0
L_0002:ldarg.1
L_0003:callvirt实例!1[mscorlib]System.Collections.Generic.Dictionary`2::get_项(!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:没有
L_0012:ldloc.0
L_0013:dup
L_0014:ldfld int32 AddableDictionary.IntegerHolder::i
L_0019:ldc.i4.1
L_001a:添加
L_001b:stfld int32 AddableDictionary.IntegerHolder::i
L_0020:没有
L_0021:br.s L_0033
L_0023:没有
L_0024:ldarg.0
L_0025:ldarg.1
L_0026:ldc.i4.1
L_0027:newobj实例void AddableDictionary.IntegerHolder::.ctor(int32)
L_002c:callvirt实例无效[mscorlib]System.Collections.Generic.Dictionary`2::Add(!0,!1)
L_0031:没有
L_0032:没有
L_0033:ret
它只调用一次get_项-在存在对象的情况下没有额外的哈希。我变得有点邋遢,将字段公开以避免属性访问的方法调用

如果是我,我会将整个功能包装到自己的类中,并从公共视图中隐藏IntegerHolder类-以下是一个有限的版本:

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.
}
公共类可数项
{
私有类整合器
{
公共国际一级;
公共整数文件夹(){i=1;}
}
Dictionary dict=新字典();
公共无效添加(T键)
{
IntegerHolder val=dict[key];
如果(val!=null)
val.i++;
其他的
dict.Add(key,newintegerholder());
}
公共空间清除()
{
格言(Clear);
}
公共整数计数(T键)
{
IntegerHolder val=dict[key];
如果(val!=null)
返回val.i;
返回0;
}
//TODO-编写IEnumerable访问器。
}

好的,您的解决方案似乎有效。你觉得字典的替代方案怎么样?另外,如果我只做了(int)htColors[color]+1,那会改变键或值吗?感谢您对哈希表的帮助。看起来我最终还是会使用字典。如果我在这里出错,有人可以纠正我,但我相信,对于移动到堆中的任何值类型,甚至(在本例中)类型化字典(Dictionary)中的int,都会自动装箱/取消装箱。elimintate所用的字典是演员阵容的混乱。@Michael,你把终身和拳击混为一谈了。装箱仅在ValueType转换为对象时发生。将ValueType移动到强类型容器中的堆中不会导致装箱,但会改变变量的生存期。尽管ValueType最终必须由一些引用作为根。+1用于非常好的IL洞察。这说明了为什么/何时为dictionary bucket使用值类型可能是个坏主意。
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.
}