【问题标题】:comparing two lists and removing missing numbers with C#使用 C# 比较两个列表并删除缺失的数字
【发布时间】:2012-04-10 13:23:19
【问题描述】:

有两个列表:

List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4
List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });

你如何比较两个列表,在 List1 中找到缺失的数字并从 List1 中删除这些数字?更准确地说,我需要找到一种方法来指定比较的开始和结束位置。

我想这个过程应该和这个非常相似:

第 1 步。

int start_num = 3; // we know that comparisons starts at number 3
int start = list2.IndexOf(start_num); // we get index of Number (3)
int end = start + 2; // get ending position
int end_num = list2[end]; // get ending number (6)

现在我们已经在 List2 (3,5,6) 中获得了数字(和数字本身)的位置以供比较

第 2 步。 要获取 List1 中数字的位置以进行比较 - 我们可以执行以下操作:

int startlist1 = list1.IndexOf(start_num); // starting position
int endlist1 = list1.IndexOf(end_num); // ending position

范围如下:(3,4,5,6)

第 3 步。比较。棘手的部分从这里开始,我需要帮助

基本上现在我们需要比较 (3,5,6) 处的 list2 和 (3,4,5,6) 处的 list1。缺少的数字是“4”。

// I have troubles with this step but the result will be:

int remove_it = 4; // or int []

第 4 步。去除奇数。

int remove_it = 4;
list1 = list1.Where(a => a != remove_it).ToList();

效果很好,但是如果我们缺少 2 个数字会怎样?即

int remove_it = 4 // becomes int[] remove_it = {4, 0}

结果如你所料,结果是新的 List1,其中没有数字 4。

richTextBox1.Text = "" + string.Join(",", list1.ToArray()); // output: 0,1,2,3,5,6

textBox1.Text = "" + start + " " + start_num; // output: 2 3
textBox3.Text = "" + end + " " + end_num; // output: 4 6

textBox2.Text = "" + startlist1; // output: 3
textBox4.Text = "" + endlist1; // output: 6

你能帮我完成第 3 步或指出正确的方向吗?

另外,如果起始数字(start_num)是最后一个数字,你能说会发生什么,但我需要得到接下来的两个数字吗?在上面的例子中,数字是 3,5,6,,但它们应该与 5,6,06,0,1 没有区别> 或 0,1,2

【问题讨论】:

  • 我不明白“在列表 1 中查找缺失的数字并从列表 1 中删除这些项目”
  • list2 不包含数字 4,但 List1 包含。这个想法是从 list1 中删除这个数字。但是,这不是问题。问题是在给定位置开始列表比较。不是从一开始,而是让我们说 - 从最后。我们只比较列表的一小部分,而不是全部。此外,假设如果我们在列表末尾取一个起始位置是合乎逻辑的 - 由于“超出范围”错误,我们将无法比较下一个数字。这就是为什么从列表的开头继续比较至关重要的原因,即从开头取 5,6,0 - 0
  • 您需要更清楚地了解它的目的和用例。

标签: c# list comparison


【解决方案1】:

只回答第一部分:

 var list3 = list1.Intersect(list2);

这会将list3 设置为{ 0, 1, 2, 3, 4, 5, 6 } - { 0, 4 } = { 1, 2, 3, 5, 6 }

以及对第 1 步的反应:

int start_num = 3; // 我们知道比较从数字 3 开始
int start = list2.IndexOf(start_num); // 我们得到数字 (3) 的索引
int 结束 = 开始 + 2; // 获取结束位置

你从哪里得到所有这些神奇的数字 (3, + 2 )?

我认为你想太多了。

【讨论】:

  • 3 不是一个常数。它可以是列表中的任何数字。另一方面,数字 2 是恒定的。我需要比较右边的两个数字。
  • 如果“右边的两个数字”不存在怎么办?抛出超出范围的异常。除非我们从列表的开头得到这个数字。看,3,5,6 - 不会抛出异常。 5,6, - - List 中没有数字 7,所以我们想从 List 的开头继续,这就是为什么结果应该如下:5,6,0。 6,-,- 没有 7 和 8 但有 0 和 1,所以 6,0,1
【解决方案2】:
var result = list1.Intersect(list2)

如果您确实需要将结果作为列表,可以在末尾添加.ToList

【讨论】:

  • 这就是区别({ 0, 4}
  • @HenkHolterman 正确,这就是我没有仔细阅读的结果。
【解决方案3】:
        List<int> list2 = new List<int>(new[] { 1, 2, 3, 5, 6 }); // missing: 0 and 4 
        List<int> list1 = new List<int>(new[] { 0, 1, 2, 3, 4, 5, 6 });

        // find items in list 2 notin 1
        var exceptions = list1.Except(list2);

        // or are you really wanting to do a union? (unique numbers in both arrays)
        var uniquenumberlist = list1.Union(list2);

        // or are you wanting to find common numbers in both arrays
        var commonnumberslist = list1.Intersect(list2);

【讨论】:

    【解决方案4】:

    也许您应该使用 OrderedList 而不是 List...

    【讨论】:

      【解决方案5】:

      类似这样的:

      list1.RemoveAll(l=> !list2.Contains(l));
      

      【讨论】:

        【解决方案6】:

        要获取list1 中存在但list2 中不存在的数字,请使用Except 扩展方法:

        IEnumerable<int> missing = list1.Except(list2);
        

        要遍历此结果以将它们从list1 中删除,您必须意识到结果,否则它会在您更改它时从列表中读取,并且您会得到一个异常:

        List<int> missing = list1.Except(list2).ToList();
        

        现在您可以删除它们了:

        foreach (int number in missing) {
          list1.Remove(number);
        }
        

        【讨论】:

          【解决方案7】:

          我不确定我是否理解你的问题,我希望我给你的解决方案对你有好处。

          您有 2 个列表:

          列表 list2 = new List(new[] { 1, 2, 3, 5, 6 }); // 缺少:0 和 4 List list1 = new List(new[] { 0, 1, 2, 3, 4, 5, 6 });

          要从 list1 中删除 list2 中所有缺失的数字,我建议使用以下解决方案: 建立一个缺少数字的新列表:

          List diff = new List();

          然后将您需要删除的所有数字放入此列表中。现在删除过程应该很简单,只需将您添加到 diff 中的所有元素从 list2 中删除即可。

          【讨论】:

            【解决方案8】:

            我是否正确理解算法是: 1) 取 List 2 中的第一个数字并在 List1 中找到该数字, 2) 然后从列表 1 中删除所有内容,直到找到第二个数字形式 list2 (5) 3) 对 list2 中的下一个数字重复步骤 2)。?

            【讨论】:

            • 需要这些数字来定义循环内的数字范围(开始:结束)。首先,我从第二个列表中获取一系列数字,并将这些数字与第一个列表中的相同范围进行比较。如果 range2 缺少一些数字 - 我从另一个列表中删除这个数字。
            【解决方案9】:

            您可以将IntersectSkipTake 结合使用,以获得与范围相结合的交集逻辑(这里我们忽略了缺少0 的事实,因为我们跳过它):

            static void Main(string[] args)
            {
                var list1 = new List<int> { 1, 2, 3, 4, 5 };
                var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };
            
                foreach (var i in list2.Skip(3).Take(3).Intersect(list1))
                    Console.WriteLine(i); // Outputs 3 then 5.
            
                Console.Read();
            }
            

            虽然如果我是真的诚实的,我不确定要问什么 - 我唯一确定的是相交部分:

            var list1 = new List<int> { 1, 2, 3, 4, 5 };
            var list2 = new List<int> { 0, 1, 2, 3, 5, 6 };
            
            foreach (var i in list2.Intersect(list1))
                Console.WriteLine(i); // Outputs 1, 2, 3, 5.
            

            【讨论】:

              【解决方案10】:

              好的,看来我没有很好地解释这个问题,抱歉。任何有兴趣的人都可以通过查看这段代码来理解我的意思:

                      List<int> list2 = new List<int>() { 1, 2, 3, 5, 6 }; // missing: 0 and 4
                      List<int> list1 = new List<int>() { 0, 1, 2, 3, 4, 5, 6 };
              
                      int number = 3; // starting position
              
                      int indexer = list2.BinarySearch(number);
                      if (indexer < 0)
                      {
                          list2.Insert(~index, number); // don't look at this part
                      }
              
                      // get indexes of "starting position"
                      int index1 = list1.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;
                      int index2 = list2.Select((item, i) => new { Item = item, Index = i }).First(x => x.Item == number).Index;
              
                      // reorder lists starting at "starting position"
                      List<int> reorderedList1 = list1.Skip(index1).Concat(list1.Take(index1)).ToList(); //main big
                      List<int> reorderedList2 = list2.Skip(index2).Concat(list2.Take(index2)).ToList(); // main small
              
              
                      int end = 2; // get ending position: 2 numbers to the right
                      int end_num = reorderedList2[end]; // get ending number
              
                      int endlist1 = reorderedList1.IndexOf(end_num); // ending position
              
                      //get lists for comparison
                      reorderedList2 = reorderedList2.Take(end + 1).ToList();
                      reorderedList1 = reorderedList1.Take(endlist1 + 1).ToList();
              
                      //compare lists
                      var list3 = reorderedList1.Except(reorderedList2).ToList();
                      if (list3.Count != 0)
                      {
                          foreach (int item in list3)
                          {
                              list1 = list1.Where(x => x != item).ToList(); // remove from list
                          }
                      }
                      // list1 is the result that I wanted to see
              

              如果有任何方法可以优化此代码,请告诉我。干杯。

              【讨论】:

                猜你喜欢
                • 1970-01-01
                • 2022-09-27
                • 2019-08-04
                • 1970-01-01
                • 2021-12-23
                • 1970-01-01
                • 1970-01-01
                • 2017-08-28
                • 1970-01-01
                相关资源
                最近更新 更多