【问题标题】:How To Get Distinct Lists?如何获得不同的列表?
【发布时间】:2013-06-22 16:55:37
【问题描述】:

使用下面的列表,如何在不进行完整的蛮力比较的情况下从下面的列表中获取不同的列表?在示例中,list2 和 list3 是相同的,所以我只想要 list1 和 list2。

var list1 = new List<int>{1,2,3,4,5};
var list2 = new List<int>{2,3};
var list3 = new List<int>{3,2};

【问题讨论】:

    标签: c# distinct


    【解决方案1】:

    将列表替换为HashSets 的集合。

    然后你就可以写了

    hashSets.Distinct(HashSet<int>.CreateSetComparer())
    

    【讨论】:

    • 这不是假设他对不允许重复条目没问题吗?对于该操作,没有重复项是可以的,但是说重复项在其他用途​​中无效呢?
    • @FlyingStreudel:正确。如果他无视顺序,通常可以安全地假设他不想要重复。
    【解决方案2】:

    EDIT 使用 List.Sort + IEnumerable 的 .Any 和 .SequenceEqual

    public static List<List<int>> Test1(List<int>[] lists)
    {
        var result = new List<List<int>>();
        foreach(var list in lists)
        {
            list.Sort();
            if(!result.Any(elm => elm.SequenceEqual(list)))
                result.Add(list);
        }
        return result;
    }
    

    这是一个简单的基准/测试,展示了 HashSet 方法和 pre-.Sort .Any .SequenceEqual 方法。 edit http://ideone.com/x3CJ8I 当然 ideone 可能不是最好的基准测试平台,所以请随意在您自己的机器上运行它。

    using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Diagnostics;
    
    public class Demo
    {
        public static void Main()
        {
            int tries = 100;
            int count = 50;
            int size = 1000;
            Random rnd = new Random();
            List<int>[] list;
            Stopwatch sw;
    
            sw = new Stopwatch();
            for(int x=0; x<tries; x++)
            {
                list = new List<int>[count];
                for(int y=0; y<count; y++)
                {
                    list[y] = new List<int>();
                    for(int z=0; z<size; z++)
                    {
                        int n = rnd.Next();
                        list[y].Add(n);
                    }
                    if((y % 5) == 0 && y > 0)
                    { // make repeated lists for the uniqueness check
                        list[y-1] = new List<int>(list[y]);
                        list[y-1].Reverse();
                    }
                }
                sw.Start();
                Test1(list);
                sw.Stop();
            }
            Console.WriteLine( sw.Elapsed.ToString() );
    
            sw = new Stopwatch();
            for(int x=0; x<tries; x++)
            {
                list = new List<int>[count];
                for(int y=0; y<count; y++)
                {
                    list[y] = new List<int>();
                    for(int z=0; z<size; z++)
                    {
                        int n = rnd.Next();
                        list[y].Add(n);
                    }
                    if((y % 5) == 0 && y > 0)
                    { // make repeated lists for the uniqueness check
                        list[y-1] = new List<int>(list[y]);
                        list[y-1].Reverse();
                    }
                }
                sw.Start();
                Test2(list);
                sw.Stop();
            }
            Console.WriteLine( sw.Elapsed.ToString() );
        }
        public static List<List<int>> Test1(List<int>[] lists)
        {
            var result = new List<List<int>>();
            foreach(var list in lists)
            {
                list.Sort();
                if(!result.Any(elm => elm.SequenceEqual(list)))
                    result.Add(list);
            }
            return result;
        }
        public static List<HashSet<int>> Test2(List<int>[] lists)
        {
            var result = new List<HashSet<int>>();
            foreach(var list in lists)
            {
                result.Add(new HashSet<int>(list));
            }
            result = result.Distinct(HashSet<int>.CreateSetComparer()).ToList();
            return result;
        }
    }
    

    EDIT 我有时间修改测试,结果发现创建 HashSets + .Distinct 的开销与 .Sort + .Any + 非常相似。序列相等。 http://ideone.com/x3CJ8I

    【讨论】:

    • 请注意,这明显低于基于哈希的解决方案。
    • @Servy - 我不知道性能会有多明显。也许您可以对其进行基准测试。此外,仅仅因为解决方案的代码行数可能更少,并不总是保证它会更快。
    • 您假设我使用代码行作为基准的依据是什么?我不是。排序并不是一个特别便宜的操作,至少与基于散列的解决方案中正在使用的算法的渐近复杂度相比。您的第一个解决方案特别糟糕,因为您最终对每个列表进行了多次排序。
    • @Servy - 这是一个简单的测试ideone.com/gDBrrS 似乎根本没有显示出太多优势。排序小列表整数列表似乎并不困扰.NET。也许您可以修改简单的测试来证明您的观点?
    • 当然,对大小为 2 的列表进行排序会很快……您需要有一个非平凡大小的数据集才能进行有意义的性能测试。现在,如果您对几十个列表进行排序,每个列表包含几百个项目(实际上是相当少量的数据),您就可以开始了解性能差异可能是什么。如果您想查看大量数据,您可以使用包含数千或数万行的列表,这样的数据量比较适中。
    【解决方案3】:

    您也可以连接三个列表,然后执行 .Distinct()

    list<int> newList = list1.Concat(list2.Concat(list3)).Distinct();
    

    【讨论】:

    • 显然 OP 想要一个列表列表 "List>" 作为结果。这个问题有点难读。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-05-27
    • 2011-07-22
    • 1970-01-01
    • 2020-05-19
    • 2013-10-24
    • 2020-07-07
    • 2021-04-02
    相关资源
    最近更新 更多