首页 > 解决方案 > c# 从四个数字创建唯一键并检查重复项

问题描述

我有很多 4 个数字[0,1,2,1], [5,1,3,1], [0,1,2,0]. [0,1,2,1],的列表,...列表包含重复项。

我正在逐步迭代列表并检查是否已经迭代了相同的列表。在大写的情况下,第一个和最后一个列表是相同的。

目前我通过向 HashSet 添加列表来做到这一点:

HashSet<string> visited = new HashSet<string>();
string key = string.Joint(";", listOfNumbers);

if(visited.Contains(key)){
   dosomething...
   visited.Add(key);
}

我注意到将整数转换为字符串并检查哈希集中是否存在此类字符串对于大型集合可能会很慢。如果我改用整数,即 int keys = (number1) * 1000000 + (number2) * 10000 + (number3) * 100 + (number4);它会快 1/3,但这个键对于大数来说不一定是唯一的。

我认为,我缺少一些为数字列表创建唯一键并以某种方式检查重复项的基本知识。有没有比使用字符串更有效的方法来解决这个问题?

标签: c#

解决方案


您可以实现自定义IEqualityComparer<IList<T>>检查重复列表/数组:

public class ListComparer<T>: IEqualityComparer<IList<T>>
{
    private IEqualityComparer<T> _comparer;

    public ListComparer(IEqualityComparer<T> comparer = null)
    {
        _comparer = comparer ?? EqualityComparer<T>.Default;
    }

    public bool Equals(IList<T> list1, IList<T> list2)
    {
        if(list1 == null && list2 == null) return true;
        if(list1 == null || list2 == null) return false;
        return list1.SequenceEqual(list2, _comparer);
    }

    public int GetHashCode(IList<T> obj)
    {
        unchecked // Overflow is fine, just wrap
        {
            int hash = 17;
            foreach(T x in obj)
            {
                hash = hash * 23 + _comparer.GetHashCode(x);
            }
            return hash;
        }
    }
}

您可以在许多 LINQ 方法或字典中使用此比较器(如果您想将列表添加为键)或在您的HashSet<T>

List<int[]> lists = new List<int[]>
{
    new[]{0,1,2,1}, new[]{5,1,3,1}, new[]{0,1,2,0}, new[]{0,1,2,1}
};

HashSet<IList<int>> visited = new HashSet<IList<int>>(new ListComparer<int>());
foreach(var arr in lists)
{
    if(!visited.Add(arr))
    {
        Console.WriteLine($"Duplicate detected: {string.Join(",", arr)}");
        // do something ...
    }
}

输出:Duplicate detected: 0,1,2,1


推荐阅读