删除int数组列表中的重复项

cMi*_*nor 24 .net c# linq arrays

有一个int数组列表,如:

List<int[]> intArrList = new List<int[]>();
intArrList.Add(new int[3] { 0, 0, 0 });
intArrList.Add(new int[5] { 20, 30, 10, 4, 6 });  //this
intArrList.Add(new int[3] { 1, 2, 5 });
intArrList.Add(new int[5] { 20, 30, 10, 4, 6 });  //this
intArrList.Add(new int[3] { 12, 22, 54 });
intArrList.Add(new int[5] { 1, 2, 6, 7, 8 });
intArrList.Add(new int[4] { 0, 0, 0, 0 });
Run Code Online (Sandbox Code Playgroud)

你将如何删除重复(重复我的意思是列表元素具有相同的长度和相同的数字).

在示例中,我将删除元素,{ 20, 30, 10, 4, 6 }因为它被发现两次

我正在考虑按元素大小对列表进行排序,然后将每个元素循环反对休息,但我不知道该怎么做.

其他问题是,如果使用像哈希这样的其他结构会更好......如果是这样如何使用它?

Sal*_*ari 26

用途GroupBy:

var result = intArrList.GroupBy(c => String.Join(",", c))
                       .Select(c => c.First().ToList()).ToList();
Run Code Online (Sandbox Code Playgroud)

结果:

{0,0,0}

{20,30,10,4,6}

{1,2,5}

{12,22,54}

{1,2,6,7,8}

{0,0,0,0}

编辑:如果你想考虑{1,2,3,4}等于{2,3,4,1}你需要OrderBy像这样使用:

var result = intArrList.GroupBy(p => string.Join(", ", p.OrderBy(c => c)))
                       .Select(c => c.First().ToList()).ToList(); 
Run Code Online (Sandbox Code Playgroud)

编辑2:为了帮助理解LINQ GroupBy解决方案的工作原理,请考虑以下方法:

public List<int[]> FindDistinctWithoutLinq(List<int[]> lst)
{
    var dic = new Dictionary<string, int[]>();
    foreach (var item in lst)
    {
        string key = string.Join(",", item.OrderBy(c=>c));

        if (!dic.ContainsKey(key))
        {
            dic.Add(key, item);
        }
    }

    return dic.Values.ToList();
}
Run Code Online (Sandbox Code Playgroud)

  • @cMinor ......我已经为您提供了帮助理解基于LINQ的解决方案是如何工作的方法.再次看到更新的答案. (2认同)

Him*_*ere 12

您可以定义自己的实现IEqualityComparer并将其与IEnumerable.Distinct以下内容一起使用:

class MyComparer : IEqualityComparer<int[]> 
{
    public int GetHashCode(int[] instance) { return 0; } // TODO: better HashCode for arrays
    public bool Equals(int[] instance, int[] other)
    {
        if (other == null || instance == null || instance.Length != other.Length) return false;

        return instance.SequenceEqual(other);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在编写此代码以仅获取列表的不同值:

var result = intArrList.Distinct(new MyComparer());
Run Code Online (Sandbox Code Playgroud)

但是,如果您想要不同的排列,也应该以这种方式实现比较器:

public bool Equals(int[] instance, int[] other)
{
    if (ReferenceEquals(instance, other)) return true; // this will return true when both arrays are NULL
    if (other == null || instance == null) return false;
    return instance.All(x => other.Contains(x)) && other.All(x => instance.Contains(x));
}
Run Code Online (Sandbox Code Playgroud)

编辑:为了更好的GetashCode实现,你可以看看这篇文章,也在@Mick的回答中提出.


Mic*_*ick 8

这里这里提升代码.一个更通用的GetHashCode实现会使这更通用,但我相信下面的实现是最强大的

class Program
{
    static void Main(string[] args)
    {
        List<int[]> intArrList = new List<int[]>();
        intArrList.Add(new int[3] { 0, 0, 0 });
        intArrList.Add(new int[5] { 20, 30, 10, 4, 6 });  //this
        intArrList.Add(new int[3] { 1, 2, 5 });
        intArrList.Add(new int[5] { 20, 30, 10, 4, 6 });  //this
        intArrList.Add(new int[3] { 12, 22, 54 });
        intArrList.Add(new int[5] { 1, 2, 6, 7, 8 });
        intArrList.Add(new int[4] { 0, 0, 0, 0 });

        var test = intArrList.Distinct(new IntArrayEqualityComparer());
        Console.WriteLine(test.Count());
        Console.WriteLine(intArrList.Count());
    }

    public class IntArrayEqualityComparer : IEqualityComparer<int[]>
    {
        public bool Equals(int[] x, int[] y)
        {
            return ArraysEqual(x, y);
        }

        public int GetHashCode(int[] obj)
        {
            int hc = obj.Length;
            for (int i = 0; i < obj.Length; ++i)
            {
                hc = unchecked(hc * 17 + obj[i]);
            }
            return hc;
        }

        static bool ArraysEqual<T>(T[] a1, T[] a2)
        {
            if (ReferenceEquals(a1, a2))
                return true;

            if (a1 == null || a2 == null)
                return false;

            if (a1.Length != a2.Length)
                return false;

            EqualityComparer<T> comparer = EqualityComparer<T>.Default;
            for (int i = 0; i < a1.Length; i++)
            {
                if (!comparer.Equals(a1[i], a2[i])) return false;
            }
            return true;
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

编辑: IEqualityComparer的通用实现,适用于任何类型的数组: -

public class ArrayEqualityComparer<T> : IEqualityComparer<T[]>
{
    public bool Equals(T[] x, T[] y)
    {
        if (ReferenceEquals(x, y))
            return true;

        if (x == null || y == null)
            return false;

        if (x.Length != y.Length)
            return false;

        EqualityComparer<T> comparer = EqualityComparer<T>.Default;
        for (int i = 0; i < x.Length; i++)
        {
            if (!comparer.Equals(x[i], y[i])) return false;
        }
        return true;
    }

    public int GetHashCode(T[] obj)
    {
        int hc = obj.Length;
        for (int i = 0; i < obj.Length; ++i)
        {
            hc = unchecked(hc * 17 + obj[i].GetHashCode());
        }
        return hc;
    }
}
Run Code Online (Sandbox Code Playgroud)

Edit2:如果数组内的整数排序无关紧要,我会的

var test = intArrList.Select(a => a.OrderBy(e => e).ToArray()).Distinct(comparer).ToList();
Run Code Online (Sandbox Code Playgroud)