【问题标题】:How to remove duplicates in List of Class with Linq如何使用 Linq 删除类列表中的重复项
【发布时间】:2022-01-14 14:16:37
【问题描述】:

我有一个班级列表:

class GroupAssets
    {
        public string Name { get; set; }
        public List<string> Assets { get; set; }
    }

        List<GroupAssets> GroupList2 = new List<GroupAssets>{
                new GroupAssets { Name="Group1", Assets = new List<string>{ "A","B","C","D" }},
                new GroupAssets { Name="Group1", Assets = new List<string>{ "A","B","E","F" }},
                new GroupAssets { Name="Group3", Assets = new List<string>{ "A","B","H","G" }},
                new GroupAssets { Name="Group4", Assets = new List<string>{ "A","I","C","J" }}
    };

我想删除重复项并得到以下结果:

Group1 => D
Group2 => E,F
Group3 => H,G
Group4 => I,J
Duplicate => A,B,C

感谢您的帮助

【问题讨论】:

  • 所有发布的只是程序描述,但这并不能告诉我们您遇到了什么问题。你尝试过什么,遇到过什么烦恼?请edit您的帖子包含valid question,我们可以回答。提醒:确保您知道on-topic 是什么;要求我们为您编写程序、建议和外部链接都是题外话。
  • 所以我想你的列表是新的 List{ "A","B","C","D" }?而你有 group2 而不是 group1?你能纠正你的错误吗

标签: c# list linq duplicates


【解决方案1】:
         List<GroupAssets> GroupList = new List<GroupAssets>{ 
                    new GroupAssets { Name="Group1", Assets = new List<string>{ "A","B","C","D" }},
                    new GroupAssets { Name="Group1", Assets = new List<string>{ "A","B","E","F" }},
                    new GroupAssets { Name="Group3", Assets = new List<string>{ "A","B","H","G" }},
                    new GroupAssets { Name="Group4", Assets = new List<string>{ "A","I","C","J" }}
        };
    var assetList = new Dictionary<string,int>();
    foreach (var g in GroupList.Select(x=> x.Assets)) {
         g.ForEach(x=> {
             if (!assetList.ContainsKey(x)) assetList.Add(x,1);
             else assetList[x]++;
         });
    }

    var nonUnique = assetList.Where(x=> x.Value > 1).Select(x=> x.Key).ToList();
    nonUnique.ForEach(x=> { Console.WriteLine(x); });

如果您想知道重复总数的替代解决方案

【讨论】:

    【解决方案2】:

    我假设您犯了一个错误,属性 GroupAssets.Assets 包含资产列表 (new List&lt;string&gt;() {"A", "B"}),而不是列表中只有一个字符串的逗号分隔字符串列表 (new List&lt;string&gt;() {"A,B"})。

    首先,您必须弄清楚哪些是重复项。您可以按字符串“A”到“J”之一对项目进行分组,值int 是该键在所有列表中的出现次数。我们从 another Stack Overflow question 获取代码,并使用一个 SelectMany 进行增强,因为我们希望将多个列表合并为一个。

        var assetCount = GroupList
            .SelectMany(x => x.Assets)
            .GroupBy(x => x)
            .Select(s => new { Asset = s.Key, Count = s.Count() });
    

    然后我们制作重复列表,以及具有唯一资产的组列表:

        var duplicates = assetCount.Where(x => x.Count > 1).Select(x => x.Asset).ToList();
        
        var uniqueAssetsGroupList = GroupList
            .Select(x => new GroupAssets() { Name = x.Name, Assets = x.Assets.Except(duplicates).ToList() });
        
        foreach (var group in uniqueAssetsGroupList)
            Console.WriteLine(string.Format("{0} => {1}", group.Name, string.Join(",", group.Assets)));
    
        Console.WriteLine("Duplicate => {0}", string.Join(",", duplicates));
    

    【讨论】:

    • 嗨 Dialecticus,它有效!太好了谢谢!是的,抱歉,我在更正帖子的资产清单上犯了一个错误。再次感谢您的帮助:-)
    【解决方案3】:

    假设你有 类 GroupAssets { 公共字符串名称 { 获取;放; } 公共 IList 资产 { 获取;放; } }

    List<GroupAssets> GroupList = new List<GroupAssets>{
      new GroupAssets { Name="Group1", Assets = new List<string>{ "A" ,"B", "C", "D" }},
      new GroupAssets { Name="Group2", Assets = new List<string>{ "A" ,"B", "E", "F" }},
      new GroupAssets { Name="Group3", Assets = new List<string>{ "A" ,"B", "H", "G" }},
      new GroupAssets { Name="Group4", Assets = new List<string>{ "A" ,"I", "C", "J" }},
    };
    

    请注意,每个 Asset 都有 4 个项目(不是 1)您可以放置​​

    代码:

    HashSet<string> duplicates = new HashSet<string>();
    HashSet<string> all = new HashSet<string>();
    
    foreach (var item in GroupList)
      foreach (var asset in item.Assets) 
        if (!all.Add(asset))     // duplicate if all contains the asset
          duplicates.Add(asset);
    
    // removing duplicates from each Asset
    foreach (var item in GroupList)
      item.Assets.RemoveAll(item => duplicates.Contains(item));
    

    我们来看看:

    string report = string.Join(Environment.NewLine, GroupList
      .Select(item => $"{item.Name} => {string.Join(", ", item.Assets)}"));
    
    Console.WriteLine(report);
    
    Console.WriteLine("Duplicate => {string.Join(", ", duplicates)}");
    

    结果:

    Group1 => D
    Group2 => E, F
    Group3 => H, G
    Group4 => I, J
    Duplicate => A, B, C
    

    但是,如果每个 Assets 包含 1 个逗号分隔项,则应添加 SplitJoin

    HashSet<string> duplicates = new HashSet<string>();
    HashSet<string> all = new HashSet<string>();
    
    foreach (var item in GroupList)
      foreach (var asset in item.Assets.SelectMany(list => list.Split(','))) 
        if (!all.Add(asset)) 
          duplicates.Add(asset);
    
    foreach (var item in GroupList) {
      item.Assets = item
        .Assets
        .Select(asset => asset.Split(',').Where(c => !duplicates.Contains(c)))
        .Where(asset => asset.Any())
        .Select(asset => string.Join(",", asset))
        .ToList();
    }
    

    【讨论】:

      【解决方案4】:

      找到唯一的重复项,然后使用 except 从资产列表中删除重复项

        [Fact]
              public void TestRemoveDuplicate()
              {
                  List<GroupAssets> GroupList = new List<GroupAssets>{
                  new GroupAssets { Name="Group1", Assets = new List<string>{ "A" ,"B", "C", "D" }},
                  new GroupAssets { Name="Group2", Assets = new List<string>{ "A" ,"B", "E", "F" }},
                  new GroupAssets { Name="Group3", Assets = new List<string>{ "A" ,"B", "H", "G" }},
                  new GroupAssets { Name="Group4", Assets = new List<string>{ "A" ,"I", "C", "J" }},
                  };
                  IList<String> duplicates = new List<String>();
                  foreach (var item in GroupList)
                  {
                      foreach (var element in item.Assets)
                      {
                          if (GroupList.Where(e =>e.Name!=item.Name && e.Assets.Contains(element)).Any())
                          {
                              if (duplicates.Contains(element) == false) { duplicates.Add(element); }
                          }
                      }
                  }
                  foreach (var item in GroupList)
                  {
                      item.Assets = item.Assets.Except(duplicates).ToList();
                      string result = "";
                      foreach (var element in item.Assets)
                      {
                          result += element + " ";
                      }
                      _output.WriteLine($"Name: {item.Name} Asset: {result}");
                  }
                  Assert.True(duplicates.Count() > 0);
              }
      

      输出:

      Name: Group1 Asset: D 
      Name: Group2 Asset: E F 
      Name: Group3 Asset: H G 
      Name: Group4 Asset: I J 
      

      【讨论】:

        【解决方案5】:
        List<string> tempList =  new List<string>();
        Dictionary<string, int> keyValuePairs = new Disctionary<string, int>();
        
        GroupList.ForEach(x => {
            tempList.AddRange(x.Assets);
        });
        
        tempList.ForEach(X => {
            if(!keyValuePairs.Keys.Contains(x))
            {
                keyValuePairs.Add(x,1);
            }
            else 
            {
                keyValuePairs[x]++;
            }
        });
        
        tempList.Clear();
        
        tempList.AddRange(keyValuePairs.Where(x => x.Value > 1).Select(x => x.Key));
        
        GroupList.ForEach(x => {
            var temp = x.Assets;
            x.Assets = temp.Except(tempList).ToList();
        });
        

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2017-11-28
          • 2020-03-30
          相关资源
          最近更新 更多