我有类似这样的数据。
原始数据:
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列(降序)应用排序,如果在第一个位置找到唯一记录,则返回该结果,否则仅对不明确的记录应用下一个排序条件,即重复第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步:仅对不明确的结果应用下一个排序条件,即column5(降序)
6-> B-> 1-> 2008-> 2011 //唯一记录
3-> B-> 1-> 2008-> 2008
因此最终列表将包含以下结果。
5-> A-> 2-> 2008-> 2009
6-> B-> 1-> 2008-> 2011
因此,我想在应用每种排序标准后从结果中获取唯一数据。我不知道我是否能够以更好的方式解释我的问题,我知道通过使用for循环并比较数据我可以解决它,但只需要帮助就可以最好地解决它。
答案 0 :(得分:1)
您可以在此使用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());
}
}
首先我将其分组(您称它为partition),然后我根据您的需求进行排序,使其变得动态并获得第一条记录。
答案 1 :(得分:0)
对我来说,最好的方法是,这种方法涉及的循环次数最少:
第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).
让我知道您是否需要正确的语法。
答案 2 :(得分:0)
我创建了一个类似于以下的类来表示您的数据
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会自动将提到的字段升序。 希望对您有所帮助!