簡體   English   中英

檢查兩個列表<int>是相同的數字

[英]Check two List<int>'s for the same numbers

我有兩個列表,我想檢查相應的數字。

例如

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。

您可以使用 .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();

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);

您可以像 LINQ 那樣有效地做到這一點 - 使用一組。 現在在 3.5 之前我們還沒有合適的集合類型,所以你需要使用Dictionary<int,int>或類似的東西:

  • 創建一個Dictionary<int, int>並使用該元素作為條目的鍵和值從列表a中填充它。 (條目中的值根本不重要。)
  • 為交叉點創建一個新列表(或將其寫為迭代器塊,無論如何)。
  • 遍歷列表 b,並使用 dictionary.ContainsKey 檢查:如果是,則向列表中添加一個條目或生成它。

那應該是 O(N+M) (即在兩個列表大小中都是線性的)

請注意,如果列表 b 包含重復項,這將為您提供重復的條目。 如果你想避免這種情況,當你第一次在列表b中看到字典條目時,你總是可以更改它的值。

您可以對第二個列表進行排序並遍歷第一個列表,並為每個值對第二個列表進行二進制搜索。

如果兩個列表都已排序,您可以在 O(n) 時間內輕松完成此操作,方法是從合並排序中進行修改合並,只需“刪除”(步進計數器過去)兩個前導數字中的較低者,如果它們曾經相等,將該數字保存到結果列表中並“刪除”它們。 它需要少於 n(1) + n(2) 步。 這當然是假設它們已排序。 但是整數數組的排序並不完全昂貴 O(n log(n))... 我認為。 如果您願意,我可以將一些代碼放在一起如何做到這一點,但這個想法非常簡單。

在評論問題作者說會有

第一個列表中最多 15 個,第二個列表中最多 20 個

在這種情況下,我不會為優化而煩惱並使用 List.Contains。

對於較大的列表,可以使用散列來利用 O(1) 查找,這會導致 O(N+M) 算法,正如 Jon 指出的那樣。

哈希需要額外的空間。 為了減少內存使用,我們應該散列最短列表。

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);
    }
}

在 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);
    }
var c = a.Intersect(b);

這僅適用於 3.5 看到您的要求,我很抱歉。

如果您要從頭開始實施,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)

可能有更快的方法,但我不知道。 希望這應該證明選擇他的方法是合理的。

這是一種刪除重復字符串的方法。 將其更改為適應 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;

    }

更新:抱歉,我實際上是在合並列表,然后刪除重復項。 我將組合列表傳遞給此方法。 不完全是您正在尋找的東西。

(上一個答案 - 將 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);

哇。 迄今為止的答案看起來非常復雜。 為什么不直接使用:

 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; }

這對我來說似乎更直接......除非我錯過了部分問題。 這是完全可能的。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM