【问题标题】:C# LINQ group collection by attribute then sort each group by explicit order defined by a list [duplicate]C# LINQ 组按属性集合,然后按列表定义的显式顺序对每个组进行排序[重复]
【发布时间】:2021-11-15 18:52:23
【问题描述】:

我有一组我想要的 C# 对象

  1. 给定属性的分组
  2. 然后按另一个属性对每个组进行排序。 排序顺序由列表明确定义。
  3. 然后我只想从每个组中获取最上面的项目

例如,考虑:

data = [
  {​​​​​"name": "Alice", "country": "UK", "age": 30}​​​​​,
  {​​​​​​​"name": "Bob", "country": "KE", "age": 20}​​​​​​​,
  {​​​​​​​"name": "Charlie", "country": "UK", "age": 30}​​​​​​​,
  {​​​​​​​"name": "Alice", "country": "KE", "age": 40}​​​​​​​,
  {​​​​​​​"name": "Bob", "country": "AU", "age": 50}​​​​​​​,
  {​​​​​​​"name": "David", "country": "USA", "age": 25}​​​​​​​,
]

我想按name 分组,然后按country 对每个组进行排序,以遵循另一个集合中指定的明确顺序,例如:

var countryOrder = new List<string> { "UK", "KE", "AU", "USA"};

然后我想根据这个顺序只选择每个组的顶级成员,这样我最终会得到一个名称唯一的对象列表(例如,UKKE 中的一个AliceAUUSA) 但遵循明确定义的优先顺序。

以下是给定示例的预期输出:

output = [
  {"name": "Alice", "country": "UK", "age": 30},
  {"name": "Bob", "country": "KE", "age": 20},
  {"name": "Charlie", "country": "UK", "age": 30},
  {"name": "David", "country": "USA", "age": 25},
]

我已尝试使用以下代码:

using System;
using System.Collections.Generic;
using System.Linq;
                    
public class Program
{
    public static void Main()
    {
        var countryOrder =new List<string> { "UK", "KE", "AU", "USA"};
        
        var data = new List<ExampleDataClass> {
            new ExampleDataClass { Name = "Alice", Country = "UK", Age = 30 },
            new ExampleDataClass { Name = "Bob", Country = "KE", Age = 20 },
            new ExampleDataClass { Name = "Charlie", Country = "UK", Age = 30 },
            new ExampleDataClass { Name = "Alice", Country = "KE", Age = 40 },
            new ExampleDataClass { Name = "Bob", Country = "AU", Age = 50 },
            new ExampleDataClass { Name = "David", Country = "USA", Age = 25 }
        };
        
        var reducedData = data
            .GroupBy(x => x.Name)
            .Select(g => g.OrderBy(item => countryOrder.IndexOf(item.Country)).Min())
            .ToList();
        
        reducedData.ForEach(item => Console.WriteLine(reducedData));
    }
}

class ExampleDataClass
{
    public string Name { get; set; }
    public string Country { get; set; }
    public int Age { get; set; }
}

.Select(g =&gt; g.OrderBy(item =&gt; countryOrder.IndexOf(item.Country)).Min()) 给出运行时异常:

Run-time exception (line 50): At least one object must implement IComparable.

Stack Trace:

[System.ArgumentException: At least one object must implement IComparable.]
   at System.Collections.Comparer.Compare(Object a, Object b)
   at System.Collections.Generic.ObjectComparer`1.Compare(T x, T y)
   at System.Linq.Enumerable.Min[TSource](IEnumerable`1 source)
   at Program.<>c__DisplayClassd.<Main>b__9(IGrouping`2 g) :line 50
   at System.Linq.Enumerable.WhereSelectEnumerableIterator`2.MoveNext()
   at System.Collections.Generic.List`1..ctor(IEnumerable`1 collection)
   at System.Linq.Enumerable.ToList[TSource](IEnumerable`1 source)
   at Program.Main() :line 49

【问题讨论】:

  • data是一个JSON数组是否正确?
  • 将其作为 C# 对象的集合处理
  • data.GroupBy(g => g.name).Select(g => new { group = g.Key, items = g.OrderBy(g => g.country)}); - 类似这样,但您需要考虑 OrderBy 上的国家/地区收集
  • 您应该尝试解决手头的问题,而不仅仅是告诉我们您想要得到什么。
  • @Flater 我已经输入了代码尝试和预期的输出

标签: c# .net linq sorting


【解决方案1】:

这是我找到的解决方案:


using System;
using System.Collections.Generic;
using System.Linq;
                    
public class Program
{
    public static void Main()
    {
        var countryOrder =new List<string> { "UK", "KE", "AU", "USA"};
        
        var data = new List<ExampleDataClass> {
            new ExampleDataClass {
                Name = "Alice",
                Country = "UK",
                Age = 30,
            },
            
            new ExampleDataClass {
                Name = "Bob",
                Country = "KE",
                Age = 20,
            },
            
            new ExampleDataClass {
                Name = "Charlie",
                Country = "UK",
                Age = 30,
            },
            
            new ExampleDataClass {
                Name = "Alice",
                Country = "KE",
                Age = 40,
            },
            
            new ExampleDataClass {
                Name = "Bob",
                Country = "AU",
                Age = 50,
            },
            
            new ExampleDataClass {
                Name = "David",
                Country = "USA",
                Age = 25,
            }
        };
        
        var reducedData = data.GroupBy(x => x.Name)
                             .Select(g => g.OrderBy(item => countryOrder.IndexOf(item.Country)).First())
                             .ToList();
        
        foreach (ExampleDataClass item in reducedData) 
        {
            Console.WriteLine(string.Format("Name: \"{0}\", Country: \"{1}\", Age: {2}", item.Name, item.Country, item.Age));
        }
    }
}

class ExampleDataClass
{
    public string Name { get; set; }
    
    public string Country { get; set; }
    
    public int Age { get; set; }
}

输出

Name: "Alice", Country: "UK", Age: 30
Name: "Bob", Country: "KE", Age: 20
Name: "Charlie", Country: "UK", Age: 30
Name: "David", Country: "USA", Age: 25

链接到 dotnetfiddle https://dotnetfiddle.net/6geHtk

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2018-10-11
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多