C#从列表中删除重复项<;列表<;int>&燃气轮机;

C#从列表中删除重复项<;列表<;int>&燃气轮机;,c#,list,duplicates,removeall,C#,List,Duplicates,Removeall,例如,我很难想出从列表中删除重复项的最有效算法(我知道这看起来像int[]的列表,但这样做只是为了视觉目的: my_list[0]= {1, 2, 3}; my_list[1]= {1, 2, 3}; my_list[2]= {9, 10, 11}; my_list[3]= {1, 2, 3}; 因此,输出将是 new_list[0]= {1, 2, 3}; new_list[1]= {9, 10, 11}; 如果您有任何想法,请告诉我。我将非常感谢。您可以使用需要比较器的LINQ重载。比较

例如,我很难想出从
列表中删除重复项的最有效算法(我知道这看起来像
int[]
的列表,但这样做只是为了视觉目的:

my_list[0]= {1, 2, 3};
my_list[1]= {1, 2, 3};
my_list[2]= {9, 10, 11};
my_list[3]= {1, 2, 3};
因此,输出将是

new_list[0]= {1, 2, 3};
new_list[1]= {9, 10, 11};
如果您有任何想法,请告诉我。我将非常感谢。

您可以使用需要比较器的LINQ重载。比较器应该查看列表是否相等。请注意,列表的默认等于操作不会执行您真正想要的操作,因此比较器需要为您循环每个操作。下面是suc的一个示例h比较器:

public class SequenceComparer<T> : IEqualityComparer<IEnumerable<T>>
{
    IEqualityComparer<T> itemComparer;
    public SequenceComparer()
    {
        this.itemComparer = EqualityComparer<T>.Default;
    }

    public SequenceComparer(IEqualityComparer<T> itemComparer)
    {
        this.itemComparer = itemComparer;
    }

    public bool Equals(IEnumerable<T> x, IEnumerable<T> y)
    {
        if (object.Equals(x, y))
            return true;
        if (x == null || y == null)
            return false;
        return x.SequenceEqual(y, itemComparer);
    }

    public int GetHashCode(IEnumerable<T> obj)
    {
        if (obj == null)
            return -1;
        int i = 0;
        return obj.Aggregate(0, (x, y) => x ^ new { Index = i++, ItemHash = itemComparer.GetHashCode(y) }.GetHashCode());
    }
}
公共类SequenceComparer:IEqualityComparer
{
IEqualityComparer项目比较器;
公共序列比较器()
{
this.itemComparer=EqualityComparer.Default;
}
公共SequenceComparer(IEqualityComparer itemComparer)
{
this.itemComparer=itemComparer;
}
公共布尔等于(IEnumerable x,IEnumerable y)
{
if(对象等于(x,y))
返回true;
如果(x==null | | y==null)
返回false;
返回x.SequenceEqual(y,itemComparer);
}
public int GetHashCode(IEnumerable obj)
{
if(obj==null)
返回-1;
int i=0;
返回obj.Aggregate(0,(x,y)=>x^new{Index=i++,ItemHash=itemComparer.GetHashCode(y)}.GetHashCode());
}
}

更新:我想到了使用匿名类型从孔乐的答案中生成一个更好的散列,我将其修改并使其在我的类中工作。

构建自定义的
EqualityComparer

编辑:


将索引包括到方法
GetHashCode
中,以确保不同的顺序不相等

这个简单的程序可以满足您的需要:

using System;
using System.Collections.Generic;
using System.Linq;

namespace ConsoleApplication6
{
    class Program
    {
        static void Main(string[] args)
        {
            List<List<int>> lists = new List<List<int>>();

            lists.Add(new List<int> { 1, 2, 3 });
            lists.Add(new List<int> { 1, 2, 3 });
            lists.Add(new List<int> { 9, 10, 11 });
            lists.Add(new List<int> { 1, 2, 3 });

            var distinct = lists.Select(x => new HashSet<int>(x))
                    .Distinct(HashSet<int>.CreateSetComparer());

            foreach (var list in distinct)
            {
                foreach (var v in list)
                {
                    Console.Write(v + " ");
                }

                Console.WriteLine();
            }
        }
    }
}
使用系统;
使用System.Collections.Generic;
使用System.Linq;
命名空间控制台应用程序6
{
班级计划
{
静态void Main(字符串[]参数)
{
列表=新列表();
添加(新列表{1,2,3});
添加(新列表{1,2,3});
增加(新名单{9、10、11});
添加(新列表{1,2,3});
var distinct=lists.Select(x=>newhashset(x))
.Distinct(HashSet.CreateSetComparer());
foreach(不同格式的变量列表)
{
foreach(列表中的var v)
{
控制台。写入(v+“”);
}
Console.WriteLine();
}
}
}
}

对于小型数据集,比较器可能很有用,但如果您有1000个或更多列表>,则尝试将它们全部进行比较可能会花费很长时间


我建议您改为使用您的数据来构建一个独特的树。树的构建速度会快得多,完成后,您可以随时将您的数据带回旧的数据结构。

我想比较@Leniel Macaferi和@L.B答案的性能,因为我不确定哪一个更有效,或者差异将是显著的。结果表明,差异非常显著:

Method 1: 00:00:00.0976649 @Leniel Macaferi
Method 2: 00:00:32.0961650 @L.B
以下是我用来对它们进行基准测试的代码:

public static void Main(string[] args)
        {
            var list = new List<List<int>> {new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11, 1}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6, 7}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}};

            var sw1 = new Stopwatch();
            sw1.Start();

            for (var i = 0; i < 1_000_000; i++)
            {
                var distinct = list.Select(x => new HashSet<int>(x)).Distinct(HashSet<int>.CreateSetComparer());
            }

            sw1.Stop();
            Console.WriteLine($"Method 1: {sw1.Elapsed}");

            var sw2 = new Stopwatch();
            sw2.Start();
            for (var i = 0; i < 1_000_000; i++)
            {
                var distinct = list.GroupBy(a => string.Join(",", a)).Select(a => a.First()).ToList();

            }
            sw2.Stop();
            Console.WriteLine($"Method 2: {sw2.Elapsed}");

            Console.ReadKey();
        }
publicstaticvoidmain(字符串[]args)
{
新列表{新列表{新列表{1,2,2,3,3,1,1,2,2,2,2,3,1,3,1,3,1,1,3,1,1,1,1,1,2,2,3,3,3,3,3,3,3,3,3,1,1,1,1,2,3,3,3,1,1,1,1,1,1,1,1,1,2,1,1,2,1,1,2,1,1,2,1,2,1,1,2,1,2,1,2,1,2,1,1,2,1,2,1,1,2,1,1,1,2,1,2,1,2,1,1,2,2,1,1,1,2,2,1,2,1,2,1,2,1,2,1,1,1,1,2,1,1,新列表1、1、2、2、2、3、3、3、3、3、3、3、1、3、3、1、1、2、2、3、1、3、3、3、1、3、1、3、3、3、3、3、1、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、1、3、1、1、3、1、1、3、1、1、2、2、3、2、3、3、3、3、1、1、2、3、2、3、3、2、3、3、3、3、3、1、3、3、3、1、3、3、3、3、1、1、3、1、3、3、3、3、3、3、1、3、3、3、1、3、3、3、3、3、3、3、1、3、3、1、3、3、1、3 10,11},新列表1、1、2、2、2、3、3、3、3、3、3、1、3、3、3、1、1、2、2、3、3、1、2、3、3、3、3、3、3、3、3、3、3、1、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、3、1、1、3、1、3、1、1、1、2、2、1、2、2、2、2、3、3、3、1、1、1、3、1、1、1、2、1、3、1、1、1、3、1、1、1、1、1、2、2、1、1、2、1、1、1、2、1、2、2、2、2、1、1、2、2、1、1、2、2、2、3、2、2、3、1、1、1、1、1、1、2}};
var sw1=新秒表();
sw1.Start();
对于(变量i=0;i<1\u 000\u 000;i++)
{
var distinct=list.Select(x=>newhashset(x)).distinct(HashSet.CreateSetComparer());
}
sw1.Stop();
WriteLine($“方法1:{sw1.appeased}”);
var sw2=新秒表();
sw2.Start();
对于(变量i=0;i<1\u 000\u 000;i++)
{
var distinct=list.GroupBy(a=>string.Join(“,”,a)).Select(a=>a.First()).ToList();
}
sw2.Stop();
WriteLine($“方法2:{sw2.appeased}”);
Console.ReadKey();
}

请注意,列表中的T必须实现IComparable。如果T是自定义类型,您必须自己实现。@MichaelSallmen我展示了一个实现,它可以选择使用
IEqualityComparer
来指定如何比较
T
对象。不过,这一点很好。(未定义适当比较接口的类型上的默认相等比较器将仅检查引用相等)@Servy yes,的确如此。不过,这只是一个示例实现。编写一个好的实现并非易事(例如,请参阅Coung Le的更好的实现,它仍然存在问题)。也许在XORing之前将每个项目的哈希值乘以下一个较大的素数会更好?@TimS。我会留下一个
//来生成哈希值
,而不是把你所拥有的放进去;至少这样读者会知道他们需要自己找到一个好的算法,而不会认为这是好的。@Servy我已经用一个很好的实现。否则,我同意你的看法。是
{1,2,3
    var finalList = lists.GroupBy(x => String.Join(",", x))
                         .Select(x => x.First().ToList())
                         .ToList();
Method 1: 00:00:00.0976649 @Leniel Macaferi
Method 2: 00:00:32.0961650 @L.B
public static void Main(string[] args)
        {
            var list = new List<List<int>> {new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11, 1}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6, 7}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3,}, new List<int> {1, 2, 31, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 6}, new List<int> {1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 1, 2, 3, 9, 10, 11}};

            var sw1 = new Stopwatch();
            sw1.Start();

            for (var i = 0; i < 1_000_000; i++)
            {
                var distinct = list.Select(x => new HashSet<int>(x)).Distinct(HashSet<int>.CreateSetComparer());
            }

            sw1.Stop();
            Console.WriteLine($"Method 1: {sw1.Elapsed}");

            var sw2 = new Stopwatch();
            sw2.Start();
            for (var i = 0; i < 1_000_000; i++)
            {
                var distinct = list.GroupBy(a => string.Join(",", a)).Select(a => a.First()).ToList();

            }
            sw2.Stop();
            Console.WriteLine($"Method 2: {sw2.Elapsed}");

            Console.ReadKey();
        }