C# 的类似于 Python 的 collections.Counter 库 -> 在 C# 中获取两个字典对象之间的值差异

10

这是我如何在C#中创建一个字典。

   Dictionary<string, int> d = new Dictionary<string, int>()
    {
        {"cheese", 2},
        {"cakes", 1},
        {"milk", 0},
        {"humans", -1}  // This one's for laughs
    };

如果你有一个像这样的字典:

from collections import Counter

my_first_dict = {
    "cheese": 1,
    "cakes": 2,
    "milk": 3,
}

my_second_dict = {
    "cheese": 0,
    "cakes": 1,
    "milk": 4,
}

print Counter(my_first_dict) - Counter(my_second_dict)

>>> Counter({'cheese': 1, 'cakes': 1})

正如您所看到的,Counter 在比较字典对象时非常有用。

C# 中是否有类似的库可以让我做类似的事情,还是我必须从头开始编码?


据我所知,在.NET中没有这样的东西。 - Tim S.
我相信你可以用 Linq 来解决这个问题。 - Quintium
不要为所有事情都使用字典。C#是一种强类型语言。创建一个适当的数据模型,并使用LINQ查询您的集合,获取您想要的任何结果或投影。 - Federico Berasategui
修改了问题,我认为如果它有一个更通用的标题,这将对未来的SO用户有所帮助。 - Games Brainiac
2个回答

5

您可以将两个字典合并,然后只需几行代码就可以根据给定的操作创建一个新字典:

Dictionary<string, int> d1 = new Dictionary<string, int>();
Dictionary<string, int> d2 = new Dictionary<string, int>();

var difference = d1.Join(d2, pair => pair.Key, pair => pair.Key, (a, b) => new
{
    Key = a.Key,
    Value = a.Value - b.Value,
})
.Where(pair => pair.Value > 0)
.ToDictionary(pair => pair.Key, pair => pair.Value);

目前没有您展示的包装字典并提供-运算符的系统类,但如果需要,可以轻松地自己创建一个:

public class Counter<T> : IEnumerable<KeyValuePair<T, int>>
{
    private IEnumerable<KeyValuePair<T, int>> sequence;
    public Counter(IEnumerable<KeyValuePair<T, int>> sequence)
    {
        this.sequence = sequence;
    }

    public static Counter<T> operator -(Counter<T> first, Counter<T> second)
    {
        return new Counter<T>(first.Join(second
            , pair => pair.Key, pair => pair.Key, (a, b) =>
                new KeyValuePair<T, int>(a.Key, a.Value - b.Value))
            .Where(pair => pair.Value > 0));
    }

    public IEnumerator<KeyValuePair<T, int>> GetEnumerator()
    {
        return sequence.GetEnumerator();
    }

    IEnumerator IEnumerable.GetEnumerator()
    {
        return GetEnumerator();
    }
}

很棒的答案,你创建了一个完整的计数器类。 - Games Brainiac

2

没有内置的类似功能,但是你可以使用一些Linq:

Dictionary<string, int> first = new Dictionary<string, int>()
{
    {"cheese", 1},
    {"cakes", 2},
    {"milk", 3},
};
Dictionary<string, int> second = new Dictionary<string, int>()
{
    {"cheese", 0},
    {"cakes", 1},
    {"milk", 4},
};

var results = 
    (from x in first
     join y in second on x.Key equals y.Key
     where x.Value - y.Value > 0
     select new { x.Key, Value = x.Value - y.Value })
    .ToDictionary(p => p.Key, p => p.Value);

// returns a dictionary like { { "cheese", 1 }, { "cakes", 1 } }

不需要 Where。如果值为零或负数,则这是减法的正确结果。 - Servy
@Servy 在 OP 的例子中,生成的对象不包含“milk”的记录。我认为这是意图。 - p.s.w.g
@p.s.w.g 是的,那是我的意图。 - Games Brainiac
@p.s.w.g 非常感谢您的答复。通过您所展示的语法,我对C#的强大之处有了一些体验。 - Games Brainiac
@Servy 因为这就是 Python 的 Counter 类的工作方式。这是一段非常有趣的代码 :)。 - Martín Coll

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接