【问题标题】:advanced list comparison in C#C# 中的高级列表比较
【发布时间】:2020-03-22 14:14:55
【问题描述】:

我开始比较我的小项目的列表。到目前为止,我可以比较是否存在相同的项目,或者该项目的一个值是否适合另一个列表项目的相同值。 Atm Im 比较两个列表中的名称。我更改了一些我找到的代码。

public class TestResources
{
     public string Name;
     public int Amount;

     public TestResources(string name, int amount)
     {
          Name = name;
          Amount = amount;
     }
}

TestResources[] ListResInStock = { new TestResources("wood", 1000), new TestResources("stone", 1000), new TestResources("sand", 1000), new TestResources("water", 1000) };
TestResources[] ListResNeeded = { new TestResources("wood", 800), new TestResources("stone", 800), new TestResources("sand", 375) };

private bool ContainsResourceName(IEnumerable<TestResources> ListResNeeded, IEnumerable<TestResources> ListResInStock)
{
     bool result;

     var list1WithName = ListResNeeded.Select(s => s.Name).ToList();
     var list2WithName = ListResInStock.Select(s => s.Name).ToList();

     result = !list1WithName.Except(list2WithName).Any();

     return result;
}

函数被调用:

Console.WriteLine("ListResInStock contains ListResNeeded:   ===> " + ContainsResourceName(ListResNeeded, ListResInStock) + " <===");    // True
Console.WriteLine("ListResNeeded contains ListResInStock:   ===> " + ContainsResourceName(ListResInStock, ListResNeeded) + " <===");    // False

现在我想更改它,以便它只返回 true,如果 ressNeeded 的名称在那里并且 ressInStock 的数量 >= RessNeeded 的数量(当然对于所有资源)。

另外,如果你能详细解释这部分 var list1WithName = ListResNeeded.Select(s =&gt; s.Name).ToList(); 我会很好,因为我不能 100% 确定它是做什么的。

非常感谢您的帮助:-)

【问题讨论】:

  • LINQ 方法 Except 默认情况下使用 DefaultComparer 处理原始类型,因此您将列表投影到字符串列表(原始类型)并使用 DefaultComparer,传入您自己的比较器实现IComparer 接口。

标签: c# list lambda


【解决方案1】:

很简单

private bool ContainsResourceName(IEnumerable<TestResources> ListResNeeded, IEnumerable<TestResources> ListResInStock)
{
     return ListResNeeded.All(resNeeded => 
         ListResInStock.Any(resInStock => 
              resInStock.Name == resNeeded.Name && 
              resInStock.Amount >= resNeeded.Amount
         )
     );
}

要理解.Select.All.First以及所谓IEnumerable接口的许多其他函数的含义,你必须了解C#中的惰性求值,而且要说的太多了。

ListResNeeded.Select(s =&gt; s.Name).ToList(); 和其他带有枚举数的操作从最后更容易阅读。所以从最后开始:你列出Select函数产生的元素列表(什么?)(它产生什么?)它需要一个资源s并返回它的s.Name(这些资源来自哪里?) 来自 ListResNeeded 列表。

同样,您必须阅读更多关于 C# 中的 IEnumerator 以及一般惰性求值的信息。这是编程中的一个重要概念。

附:还有一些关于您尝试使用的代码的警告。你在那里做什么:

var list1WithName = ListResNeeded.Select(s => s.Name).ToList();
var list2WithName = ListResInStock.Select(s => s.Name).ToList();

正在制作传入函数的两个参数的完整副本(想象这些数组会大得多,复制它们有什么意义?)。

在完全遍历之前的两个列表之后,您会创建一个 新的(第三个)列表,而您实际寻找的只是一个布尔答案。

result = !list1WithName.Except(list2WithName).Any();

在您知道答案为假之前,您不必完全遍历这两个列表。你只需要找到一个first丢失的资源,然后停止搜索(它要轻得多)

【讨论】:

  • 您应该小心嵌套线性搜索。例如。如果我有两个 50 和 50 长的列表以及两个 100 和 100 长的列表,那么评估 100 个长列表所需的时间不会是原来的两倍,而是 4 倍。所以执行时间会迅速爆炸。
  • 感谢您的快速回答和优化结果!
  • @weston 我同意,但是如果不更改数据结构,您将无能为力
  • @Ineedhelpplease weston 是对的,您还应该考虑存储资源的正确数据结构。把所有东西都放在一个列表中然后搜索它们就像把所有东西都扔到一堆然后试图在里面找到一千根针
  • 即使在此方法中,您也可以通过将其中一个列表复制到新的Dictionary 来提高效率。
猜你喜欢
  • 2014-07-08
  • 1970-01-01
  • 2020-01-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-01-31
  • 2023-04-04
相关资源
最近更新 更多