在一个整数列表的列表中查找重复项

3

在一个由整数列表组成的列表中,找到重复项的最佳方法是什么(无论它们的位置如何)?我不需要代码,只需要解决这个问题的最佳方法(使用C#语言)。

例如:

List<List<int>> TestData = new List<List<int>>
{
     new List<int> { 1, 2, 3 },
     new List<int> { 2, 1, 3 },
     new List<int> { 6, 8, 3, 45,48 },
     new List<int> { 9, 2, 4 },
     new List<int> { 9, 2, 4, 15 },
};

这个想法是它将返回结果。
   Count | Set
----------------
   2x    | 1,2,3
   1x    | 6, 8, 3, 45, 48
   1x    | 9,2,4
   1x    | 9, 2, 4, 15

我一直在为这个看似非常简单的问题而苦恼,但出于某种原因我无法解决它。希望有人能够帮助,就像我说的那样,代码不是必需的,但非常感激。


5
定义最佳方式 - 最短的代码,最优的性能(关注内存还是速度)?最佳方式指的是既能在代码长度方面尽可能地简洁,又能在性能方面达到最优水平。关于内存和速度哪个更重要,则取决于具体应用场景。 - Ondrej Svejdar
你可以使用字典或哈希表来实现这个。 - Praburaj
也许你应该尝试Linq... TestData.Select(L => L.Sort()).GroupBy(x => x) => 返回的值是按列表分组的。 - Sebastian Siemens
如果列表中不包含重复项,则@Jodrell的解决方案是最佳的。如果您能提供一些反馈,那就太好了。 - Ivan Stoev
@IvanStoev同意,如果列表不应被视为集合而是序列,则需要详细说明相等规则。 - Jodrell
4个回答

6

首先,您希望将您的列表转换为集合:

var testSets = testData.Select(s => new HashSet<int>(s));

然后您可以将集合分组以进行相等性比较。
var groupedSets = testSets.GroupBy(s => s, HashSet<int>.CreateSetComparer());

这里有一个完全可行的示例

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

public class Test
{
    public static void Main()
    {
        var testData = new List<List<int>>
        {
             new List<int> { 1, 2, 3 },
             new List<int> { 2, 1, 3 },
             new List<int> { 6, 8, 3, 45, 48 },
             new List<int> { 9, 2, 4 },
             new List<int> { 9, 2, 4, 15 }
        };

        var testSets = testData.Select(s => new HashSet<int>(s));

        var groupedSets = testSets.GroupBy(s => s, HashSet<int>.CreateSetComparer());

        foreach(var g in groupedSets)
        {
            var setString = String.Join(", ", g.Key);
            Console.WriteLine($" {g.Count()} | {setString}");
        }
    }
}

感谢您提供的优雅解决方案,但唯一的问题是我还需要比较集合的长度。因此,像{1,2,3}、{3,1,2}和{1,2,3,4}这样的列表应该返回:2x 1,2,3和1x 1,2,3,4。 - John
@John 这就是会发生的事情。{1, 2, 3} 等于 {3, 1, 2} 但不等于 {1, 2, 3, 4}。您可以点击链接查看演示。 - Jodrell

0

你应该使用适当的数据结构来满足你的需求。在这种情况下,你有一个字典,其中包含了一组整数:

IDictionary<ISet<int>, int>

如果您不想使用LINQ(这可能是最佳实践,请参见其他答案),则可以按以下方式构建它:

var result = new Dictionary<HashSet<int>, int>();

foreach (var i in TestData)
{
    var key = new HashSet<int>(i);

    int count;

    result.TryGetValue(key, out count);
    result[id] = count + 1;
}

0

请尝试以下操作:

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

namespace ConsoleApplication1
{
    class Program
    {
        static void Main(string[] args)
        {
            List<List<int>> TestData = new List<List<int>>
            {
                 new List<int> { 1, 2, 3 },
                 new List<int> { 2, 1, 3 },
                 new List<int> { 6, 8, 3 },
                 new List<int> { 9, 2, 4 },
            };

            var values = TestData.SelectMany(x => x).GroupBy(x => x).ToList();
            var counts = values.Select(x => new { value = x.Key, times = x.Count() }).ToList();

            var times = counts.GroupBy(x => x.times).Select(x => new { key = x.Key, values = x.Select(y => y.value).ToList() }).OrderBy(x => x.key).ToList();

        }

    }

}

0
 The answer of @Jodrell is very elegant (for me is the best), but only say depends of what you want the answer is correct

    For the nex data
                var testData = new List<List<int>>
            {
                 new List<int> { 1, 2, 3 },
                 new List<int> { 1, 2, 3 },
                 new List<int> { 1, 2, 3, 3 },
            }

    The result is going to be:

    Count | Set

    3x |  1,2,3

    And not the next:

    Count | Set

    2x    | 1,2,3

       1x    | 1,2,3,3

    So depends of your question...


    Ok, so, with the last one this is my code, is not fancy and you can improve a lot of things
    enter code here


 using System;
    using System.Collections.Generic;
    using System.Linq;
    using System.Text;
    using System.Threading.Tasks;

    namespace TestListInt
    {
        class Program
        {
            public class WrapperListInt
            {
                public List<int> list;
                public WrapperListInt(List<int> list)
                {
                    this.list = list;
                }

                public override int GetHashCode()
                {
                    return 0;
                }
                public override bool Equals(object obj)
                {
                    if (this == obj) return true;
                    WrapperListInt o = obj as WrapperListInt;
                    if (this.list.Count != o.list.Count) return false;

                    for (int i = 0; i < this.list.Count; i++)
                    {
                        if (this.list[i] != o.list[i]) { return false; }
                    }

                    return true;
                }
            }
            public Program() {
                var testData = new List<List<int>>
            {
                 new List<int> { 1, 2, 3 },
                 new List<int> { 1, 3, 2 },
                 new List<int> { 1, 2, 3, 3 },
                 new List<int> { 6, 8, 3, 45,48 },
                 new List<int> { 9, 2, 15, 4 },
                 new List<int> { 9, 2, 4},
                 new List<int> { 9, 2, 4, 15 }
            };

                //Order every list
                foreach (var td in testData)
                {
                    td.Sort();
                }


                Dictionary<WrapperListInt, int> dic = new Dictionary<WrapperListInt, int>();
                foreach (var listInt in testData)
                {
                    WrapperListInt aux = new WrapperListInt(listInt);
                    int countList;
                    if (dic.TryGetValue(aux, out countList))
                    {
                        dic[aux]++;
                    }
                    else
                    {
                        dic.Add(aux, 1);
                    }
                }

                foreach (var d in dic)
                {
                    var setString = String.Join(", ", d.Key.list);
                    Console.WriteLine($" {d.Value} | {setString}");
                }
            }
            static void Main(string[] args)
            {
                new Program();
            }
        }
    }

我指的是最后一个。 - John
@John,我放了代码,但是格式搞乱了,抱歉。 - user244943

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