从结果列表中获取唯一数据
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());
}
}
首先我分组(你称之为分区),然后我根据你的需要进行排序,使其动态化并获得第一条记录。
我有这样的数据。
原始数据:
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());
}
}
首先我分组(你称之为分区),然后我根据你的需要进行排序,使其动态化并获得第一条记录。