【问题标题】:How to properly use LINQ Query on List<KeyValuePair<string, string> to create Dictionary<KeyValuePair<string, string>, int>?如何正确使用 List<KeyValuePair<string, string> 上的 LINQ 查询来创建 Dictionary<KeyValuePair<string, string>, int>?
【发布时间】:2019-06-18 16:01:56
【问题描述】:

我正在尝试在 List&lt;KeyValuePair&lt;string, string&gt;&gt; 上创建一个 LINQ 查询,它告诉我列表中有多少(如果有)KeyValue 重复项。为此,我尝试创建一个Dictionary&lt;KeyValuePair&lt;string, string&gt;, int&gt;,其中字典的键是列表中的 KeyValuePair,字典的值是该对在原始列表中出现的次数。我的代码可以编译,但它目前告诉我列表中的每个 KeyValuePairs 都是重复的。

为了提供一些上下文,在 .NET/DNN Web 表单中调用此方法来验证我们的一个客户上传的文件;表格可以有重复的发票号,但不能有重复的发票和部件号;因此,List&lt;KeyValuePair&lt;string, string&gt;&gt; 代表一对发票编号和零件编号。字典的 int 值应该报告每个发票和零件编号对出现在主列表中的次数。正在从包含文件上传数据的 GridView 控件中提取数据。

在过去的几个小时里,我在这里阅读了一堆 LINQ 文章,试图复制用于创建具有这样一个列表的字典的代码,但我没有成功。这篇文章提供了很多有用的信息:

C# LINQ find duplicates in List

另外,请注意,此代码是在 DNN 中实现的,这使得调试非常困难。我无法逐步检查我的代码以确定问题,所以请耐心等待。

private void CheckBranchNumbersFile(GridView Upload)
{
    List<KeyValuePair<string, string>> invoiceAndPart = new List<KeyValuePair<string, string>>();

    for (int i = 0; i < Upload.Rows.Count; ++i)
    {
        KeyValuePair<string, string> pair = new KeyValuePair<string, string>(Upload.Rows[i].Cells[2].ToString(), Upload.Rows[i].Cells[5].ToString());
        invoiceAndPart.Add(pair);
    }

    List<KeyValuePair<string, string>> invoiceAndPartUnsorted = new List<KeyValuePair<string, string>>(invoiceAndPart);

    var query = invoiceAndPart.GroupBy(x => x).Where(g => g.Count() > 1).ToDictionary(x => x.Key, y => y.Count());
    foreach (KeyValuePair<KeyValuePair<string, string>, int> invPartCount in query)
    {
        int count = invPartCount.Value;
        if (count > 1)
        {
            IsNotValid = true;
            for (int i = 0; i < invoiceAndPartUnsorted.Count; ++i)
            {
                if (invoiceAndPartUnsorted[i].Key.Equals(invPartCount.Key.Key) && invoiceAndPartUnsorted[i].Value.Equals(invPartCount.Key.Value))
                {
                    // This block highlights the cells on the review screen for the client to see erroneous data
                    Upload.Rows[i].Cells[2].BackColor = Color.Red;
                    Upload.Rows[i].Cells[5].BackColor = Color.Red;
                    Upload.Rows[i].Cells[2].ToolTip = "Cannot have duplicate invoice AND part numbers";
                    Upload.Rows[i].Cells[5].ToolTip = "Cannot have duplicate invoice AND part numbers";
                }
            }
        }
    }
}

请参阅以下可重现的示例:

// Populate list with sample invoice/part numbers, including some duplicates

List<KeyValuePair<string, string>> data = new List<string, string>();
KeyValuePair<string, string> sample1 = new KeyValuePair<string, string>("ABC", "100");
KeyValuePair<string, string> sample2 = new KeyValuePair<string, string>("FFF", "250");
KeyValuePair<string, string> sample3 = new KeyValuePair<string, string>("XYZ", "100");
KeyValuePair<string, string> sample4 = new KeyValuePair<string, string>("ABC", "100");
KeyValuePair<string, string> sample5 = new KeyValuePair<string, string>("ABC", "100");

data.Add(sample1);
data.Add(sample2);
data.Add(sample3);
data.Add(sample4);
data.Add(sample5);

// Create copy of data before data is grouped by LINQ query

List<KeyValuePair<string, string>> data2 = new List<string, string>(data);

// Perform LINQ Query to create Dictionary<KeyValuePair<string, string>, int> that reports number of occurences of each KeyValuePair<string, string> in @variable ata

var query = data.GroupBy(x => x).Where(g => g.Count() > 1).ToDictionary(x => x.Key, y => y.Count());

// Using foreach loop, identify the indices in @variable data2 that contain duplicated entries
foreach (KeyValuePair<KeyValuePair<string, string>, int> pair in query)
{
   int count = pair.Value;

   // This pair represents a duplicate because its value > 1
   if (count > 1)
   {
      // Find the entry in data2 that matches this pair
      for (int i = 0; i < data2.Count; ++i)
      {
         if (data2[i].Equals(pair.Key))
         {
            Console.WriteLine("Match in list data2 found at index: " + i);
         }
      }
   }
}

// The console should write:
// Match in list data2 found at index: 0
// Match in list data2 found at index: 3
// Match in list data3 found at index: 4

// Thank you! :)

我希望审核屏幕仅将具有重复发票和零件编号的行的单元格标记为错误,但它会为文件中的每一行数据标记这些单元格。例如,如果输入 Excel 文件共有 10 行,其中 3 行包含重复的发票和部件号,则这些单元格必须涂成红色并用工具提示进行标记,而不是全部 10 行。每行的单元格 2 和 5 分别包含发票号和部件号。这是它现在正在做的截图:https://gyazo.com/a2c8203627fe81f763c48008d0ba9e33

在此示例中,只有最后 3 行的单元格 2 和 5 应以红色突出显示;前几行中突出显示的其他单元格都可以(空字段的其他验证器)。

编辑:包括一个可重现的示例。这是我在这里的第一篇文章,所以请批评我的礼仪!谢谢!

【问题讨论】:

  • minimal, reproducible example 对您和任何试图帮助解决问题的人都有很大帮助。请尝试将此代码从您的解决方案中提取出来并对其进行重新设计,以尽可能紧密地关注问题,使其可以独立于其他任何东西运行。
  • @nlawalker 我会尽快发布更新的区块,非常感谢
  • 您的代码无法编译,但进行了明显的更改以使其编译,我得到您的评论表明应该产生的输出。现在您有了一个可重现的示例,您是否尝试将其粘贴到一个新应用程序中并在调试器中运行它以查看哪些地方没有按预期工作?
  • @nlawalker 我的一位同事正在引导我完成我编写的 LINQ 查询,我现在将对其进行调试
  • @nlawalker 没想到它会起作用!一定是我最后一个 for 循环中的问题。

标签: c# .net linq duplicates dotnetnuke


【解决方案1】:

这很好用:

         var data = new List<KeyValuePair<string, string>>
         {
            new KeyValuePair<string, string>("ABC", "100"),
            new KeyValuePair<string, string>("FFF", "250"),
            new KeyValuePair<string, string>("XYZ", "100"),
            new KeyValuePair<string, string>("ABC", "100"),
            new KeyValuePair<string, string>("ABC", "100")
         };

         // Create copy of data before data is grouped by LINQ query

         var data2 = data.ToList();

         // Perform LINQ Query to create Dictionary<KeyValuePair<string, string>, int> that reports number of occurences of each KeyValuePair<string, string> in @variable ata

         var query = data.GroupBy(x => x).Where(g => g.Count() > 1).ToDictionary(x => x.Key, y => y.Count());

         // Using foreach loop, identify the indices in @variable data2 that contain duplicated entries
         foreach (var pair in query)
         {
            int count = pair.Value;

            // This pair represents a duplicate because its value > 1
            if (count > 1)
            {
               // Find the entry in data2 that matches this pair
               for (int i = 0; i < data2.Count; ++i)
               {
                  if (data2[i].Equals(pair.Key))
                  {
                     Console.WriteLine("Match in list data2 found at index: " + i);
                  }
               }
            }
         }

【讨论】:

  • 这很奇怪,但很高兴知道!我不认为我的逻辑有效。干杯。
  • 几个小问题。看看“var data2 = data.ToList();”要克隆您的列表,您需要在初始化正确的类型时更加小心,否则很好。
  • 谢谢你,先生:)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2011-03-05
  • 1970-01-01
  • 2010-11-22
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多