检查两个List <int>的相同数字</int>

时间:2009-01-26 14:55:03

标签: c# .net generics list

我有两个List,我想检查相应的数字。

例如

List<int> a = new List<int>(){1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};

应该给出结果4。 有没有一种简单的方法可以做到这一点而不需要在列表中进行太多循环?

我在3.0上的项目,我需要这个,所以没有Linq。

12 个答案:

答案 0 :(得分:30)

您可以使用.net 3.5 .Intersect()扩展方法: -

List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };

List<int> common = a.Intersect(b).ToList();

答案 1 :(得分:11)

Jeff Richter出色的PowerCollections设置了交叉点。一直运行回.NET 2.0。

http://www.codeplex.com/PowerCollections

        Set<int> set1 = new Set<int>(new[]{1,2,3,4,5});
    Set<int> set2 = new Set<int>(new[]{0,4,8,12});
    Set<int> set3 = set1.Intersection(set2);

答案 2 :(得分:9)

你可以像LINQ那样有效地做到这一点 - 用一套。现在在3.5之前我们没有一个合适的集合类型,所以你需要使用Dictionary<int,int>或类似的东西:

  • 创建一个Dictionary<int, int>并使用该元素作为条目的值,从列表a填充它。 (条目中的值确实无关紧要。)
  • 为交叉点创建一个新列表(或将其写为迭代器块,无论如何)。
  • 遍历列表b,并使用dictionary.ContainsKey检查:如果是,请在列表中添加一个条目或将其生成。

那应该是O(N + M)(即两个列表大小都是线性的)

请注意,如果列表b包含重复项,则会为您提供重复的条目。如果您想避免这种情况,当您第一次在列表b中看到它时,您可以随时更改字典条目的值。

答案 3 :(得分:3)

您可以对第二个列表进行排序并遍历第一个列表,并为每个值在第二个列表上执行二进制搜索。

答案 4 :(得分:2)

如果两个列表都已排序,您可以通过从merge-sort进行修改合并,在O(n)时间内轻松完成此操作,只需“删除”(步骤一个计数器过去)两个前导数字中的较低者,如果他们永远相同,将该数字保存到结果列表并“删除”它们。它需要少于n(1)+ n(2)步。这当然是假设它们已经排序。但整数数组的排序并不是非常昂贵O(n log(n))......我想。如果你愿意,我可以把一些代码放在一起,如何做到这一点,但这个想法非常简单。

答案 5 :(得分:2)

在对问题作者的评论中说会有

  

第一个列表中最多15个,而第二个列表中最多20个   第二个清单

在这种情况下,我不打扰优化并使用List.Contains。

对于较大的列表,可以使用散列来利用O(1)查找,这会导致Jon注意到O(N + M)算法。

哈希需要额外的空间。为减少内存使用量,我们应该使用最短列表。

List<int> a = new List<int>() { 1, 2, 3, 4, 5 };
List<int> b = new List<int>() { 0, 4, 8, 12 };
List<int> shortestList;
List<int> longestList;
if (a.Count > b.Count)
{
    shortestList = b;
    longestList = a;
}
else
{
    shortestList = a;
    longestList = b;                
}

Dictionary<int, bool> dict = new Dictionary<int, bool>();
shortestList.ForEach(x => dict.Add(x, true));

foreach (int i in longestList)
{
    if (dict.ContainsKey(i))
    {
        Console.WriteLine(i);
    }
}

答案 6 :(得分:2)

在3.0上测试

    List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
    List<int> b = new List<int>() { 0, 4, 8, 12 };
    List<int> intersection = new List<int>();
    Dictionary<int, int> dictionary = new Dictionary<int, int>();
    a.ForEach(x => { if(!dictionary.ContainsKey(x))dictionary.Add(x, 0); });
    b.ForEach(x => { if(dictionary.ContainsKey(x)) dictionary[x]++; });
    foreach(var item in dictionary)
    {
        if(item.Value > 0)
            intersection.Add(item.Key);
    }

答案 7 :(得分:1)

var c = a.Intersect(b);

这只适用于3.5,看到了你的要求我的应用。

答案 8 :(得分:0)

如果您要从头开始实施,ocdecio推荐的方法是一个很好的方法。看一下与nieve方法相比的时间复杂度,我们看到:

排序/二元搜索方法: T~ = O(n log n)+ O(n)* O(log n)〜= O(n log n)

循环遍历两个列表(nieve方法): T = = O(n)* O(n)〜= O(n ^ 2)

可能有一种更快的方法,但我不知道。希望这有理由选择他的方法。

答案 9 :(得分:0)

这是删除重复字符串的方法。将此更改为适应int,它将正常工作。

public List<string> removeDuplicates(List<string> inputList)
    {
        Dictionary<string, int> uniqueStore = new Dictionary<string, int>();
        List<string> finalList = new List<string>();

        foreach (string currValue in inputList)
        {
            if (!uniqueStore.ContainsKey(currValue))
            {
                uniqueStore.Add(currValue, 0);
                finalList.Add(currValue);
            }
        }
        return finalList;

    }

更新:抱歉,我实际上正在组合列表,然后删除重复项。我将组合列表传递给此方法。不完全是你想要的。

答案 10 :(得分:0)

(之前的答案 - 将IndexOf更改为包含,因为IndexOf首先转换为数组)

看到它是两个小清单,下面的代码应该没问题。不确定是否有像Java这样的交集方法的库(虽然List不是一个集合所以它不起作用),我知道有人指出PowerCollection库有一个。

List<int> a = new List<int>() {1, 2, 3, 4, 5};
List<int> b = new List<int>() {0, 4, 8, 12};

List<int> result = new List<int>();
for (int i=0;i < a.Count;i++)
{
    if (b.Contains(a[i]))
        result.Add(a[i]);
}

foreach (int i in result)
    Console.WriteLine(i);

更新2: HashSet是一个愚蠢的答案,因为它是3.5而不是3.0

更新:HashSet似乎是一个明显的答案:

// Method 2 - HashSet from System.Core
HashSet<int> aSet = new HashSet<int>(a);
HashSet<int> bSet = new HashSet<int>(b);
aSet.IntersectWith(bSet);
foreach (int i in aSet)
    Console.WriteLine(i);

答案 11 :(得分:0)

哇。到目前为止,答案看起来非常复杂。为什么不直接使用:

List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 };
List<int> b = new List<int>() { 0, 4, 8, 12 };

...

public List<int> Dups(List<int> a, List<int> b)
{
    List<int> ret = new List<int>();

    foreach (int x in b)
    { 
        if (a.Contains(x))
        {
           ret.add(x);
        }
    }

    return ret;
}

List<int> a = new List<int>() { 1, 2, 3, 4, 5, 12, 13 }; List<int> b = new List<int>() { 0, 4, 8, 12 }; ... public List<int> Dups(List<int> a, List<int> b) { List<int> ret = new List<int>(); foreach (int x in b) { if (a.Contains(x)) { ret.add(x); } } return ret; }

这对我来说似乎更为直截了当......除非我错过了部分问题。这完全有可能。