从结果列表中获取唯一数据

Get unique data from list of result

我有这样的数据。

原始数据:
1 -> A -> 1 -> 2011 -> 2009
2 -> A -> 1 -> 2011 -> 2010
3 -> B -> 1 -> 2008 -> 2008
4 -> B -> 1 -> 2009 -> 2009
5 -> A -> 2 -> 2008 -> 2009
6 -> B -> 1 -> 2008 -> 2011

第 1 步:按第 2 列进行分区。
1 -> A -> 1 -> 2011 -> 2009
2 -> A -> 1 -> 2011 -> 2010
5 -> A -> 2 -> 2008 -> 2009
3 -> B -> 1 -> 2008 -> 2008
4 -> B -> 1 -> 2009 -> 2009
6 -> B -> 1 -> 2008 -> 2011

第 2 步:按第 3 列(降序)应用排序,如果在第一个位置 return 找到唯一记录,则结果否则仅对不明确的记录应用下一个排序标准,即重复步骤 #2。
5 -> A -> 2 -> 2008 -> 2009 //唯一记录
1 -> A -> 1 -> 2011 -> 2009
2 -> A -> 1 -> 2011 -> 2010
3 -> B -> 1 -> 2008 -> 2008
4 -> B -> 1 -> 2009 -> 2009
6 -> B -> 1 -> 2008 -> 2011

所以现在我们的结果将是这样的。 清单 1:
5 -> A -> 2 -> 2008 -> 2009

列表 2:由于我们已经能够在 "A" 中找到唯一记录,因此从剩余列表
中删除其数据 3 -> B -> 1 -> 2008 -> 2008
4 -> B -> 1 -> 2009 -> 2009
6 -> B -> 1 -> 2008 -> 2011

第 3 步:应用下一个排序标准,即 column4(降序),但位置 1 的数据不明确
3 -> B -> 1 -> 2008 -> 2008
6 -> B -> 1 -> 2008 -> 2011
4 -> B -> 1 -> 2009 -> 2009

第 4 步:仅对不明确的结果应用下一个排序标准,即第 5 列(降序)
6 -> B -> 1 -> 2008 -> 2011 //唯一记录
3 -> B -> 1 -> 2008 -> 2008

因此最终列表将包含如下结果。
5 -> A -> 2 -> 2008 -> 2009
6 -> B -> 1 -> 2008 -> 2011

所以我想在应用每个排序标准后从结果中获取唯一数据。我不知道我是否能够以更好的方式解释我的问题,我知道通过使用 for 循环和比较数据我可以解决它,但只需要帮助以最好的方式解决它。

对我来说,最好的方法,即涉及最少循环的方法是这样的:

您需要第 2 列上的 LINQ 组(第 1 步:按第 2 列分区。)

这将为您提供两个组的匿名列表,其中包含组 [0] 中 A 的所有元素和组 [1] 中 B 的所有元素。

所以你需要在组数组上循环,并在对第 3 列降序应用排序后取第一个元素,然后按第 4 列降序,然后按第 5 列降序。这里的重要部分是 ThenBy。

所以基本上可以归结为:

For each objGroup in dtb.Group(....)
objGroup.OrderByDescending(Column3)
.ThenByDescending(Column4)
.ThenByDescending(Column5).

如果您需要正确的语法,请告诉我。

我创建了一个如下所示的 class 来表示您的数据

public class TestClass
    {
        private int _col1;
        private char _col2;
        private int _col3;
        private int _col4;
        private int _col5;

        public TestClass(int c1, char c2, int c3, int c4, int c5)
        {
            _col1 = c1;
            _col2 = c2;
            _col3 = c3;
            _col4 = c4;
            _col5 = c5;
        }

        public int Col1
        {
            get { return _col1; }
            set { _col1 = value; }
        }

        public char Col2
        {
            get { return _col2; }
            set { _col2 = value; }
        }

        public int Col3
        {
            get { return _col3; }
            set { _col3 = value; }
        }

        public int Col4
        {
            get { return _col4; }
            set { _col4 = value; }
        }

        public int Col5
        {
            get { return _col5; }
            set { _col5 = value; }
        }
    }

然后我写了这个程序,似乎在一定程度上满足了您的需求

List<TestClass> test = new List<TestClass>();

            test.Add(new TestClass(1, 'A', 1, 2011, 2009));
            test.Add(new TestClass(2, 'A', 1, 2011, 2010));
            test.Add(new TestClass(3, 'B', 1, 2008, 2008));
            test.Add(new TestClass(4, 'B', 1, 2009, 2009));
            test.Add(new TestClass(5, 'A', 2, 2008, 2009));
            test.Add(new TestClass(6, 'B', 1, 2008, 2011));

            var first_ordered = from t in test
                                orderby t.Col2, t.Col3 descending, t.Col4 descending, t.Col5 descending
                                group new { t.Col1, t.Col3, t.Col4, t.Col5 } by t.Col2 into p
                                select new
                                {
                                    Col1 = p.First().Col1,
                                    Col2 = p.Key,
                                    Col3 = p.First().Col3,
                                    Col4 = p.First().Col4,
                                    Col5 = p.First().Col5
                                };

            foreach(var f in first_ordered) 
            {
                Console.WriteLine($"{f.Col1}, {f.Col2}, {f.Col3}, {f.Col4}, {f.Col5}");
            }

它适用于'A'分区,对于'B'不适用,但您的解释中有些地方似乎不正确:当您在文中描述步骤3时您要求第 4 列按降序排列,但在您放置的数据中,它们是按升序排列的。所以,我遵循了你写的文本,如果你想要升序,你只需采用我的代码,删除 orderby 子句中的 "descending" ,Linq 将自动对提到的字段进行升序排序。 希望对您有所帮助!

您可以将 linq 与此结合使用:

namespace ConsoleApp4
{
    class SortOrder
    {
    public Func<DataRec, object> PropName { get; set; }
    public bool Ascending { get; set; }
    }

    public class DataRec
    {
        public int ID { get; set; }
        public string Name { get; set; }
        public int Order { get; set; }
        public int Year1 { get; set; }
        public int Year2 { get; set; }
    }
    class Program
    {


        static void Main(string[] args)
        {
           List<DataRec> myData = new List<DataRec>();

        myData.Add(new DataRec() { ID = 1, Name = "A", Order = 1, Year1 = 2011, Year2 = 2009 });
        myData.Add(new DataRec() { ID = 2, Name = "A", Order = 1, Year1 = 2011, Year2 = 2010 });
        myData.Add(new DataRec() { ID = 3, Name = "B", Order = 1, Year1 = 2008, Year2 = 2008 });
        myData.Add(new DataRec() { ID = 4, Name = "B", Order = 1, Year1 = 2009, Year2 = 2009 });
        myData.Add(new DataRec() { ID = 5, Name = "A", Order = 2, Year1 = 2008, Year2 = 2009 });
        myData.Add(new DataRec() { ID = 6, Name = "B", Order = 1, Year1 = 2008, Year2 = 2011 });

        //var orderedData = myData.GroupBy(x=>x.Name, (key, group) =>group.OrderByDescending(x => x.Order).ThenBy(x => x.Year1).ThenByDescending(x => x.Year2).First()).ToList();
        List<SortOrder> sorting = new List<SortOrder>();
        sorting.Add(new SortOrder() { PropName = x => x.Order, Ascending = false });
        sorting.Add(new SortOrder() { PropName = x => x.Year1, Ascending = true });
        sorting.Add(new SortOrder() { PropName = x => x.Year2, Ascending = false });

        var orderedData = myData.GroupBy(x=>x.Name);

        IOrderedEnumerable<DataRec> sorted;
        List<DataRec> result = new List<DataRec>();

        foreach (var oneGroup in orderedData)
        {
            sorted = null;
            foreach (SortOrder oneSort in sorting)
            {
                if (sorted == null)
                {
                    sorted = oneSort.Ascending ? oneGroup.OrderBy(oneSort.PropName) : oneGroup.OrderByDescending(oneSort.PropName);                      
                }
                else
                {
                    sorted = oneSort.Ascending ? sorted.ThenBy(oneSort.PropName): sorted.ThenByDescending(oneSort.PropName);
                }
            }
            result.Add(sorted.First());
        }
    }

首先我分组(你称之为分区),然后我根据你的需要进行排序,使其动态化并获得第一条记录。