C# 带扭曲的Linq排序
我有以下记录 最后2个是记录3和4的子项,我希望能够按数量对记录进行排序,但应该是先对非兴趣(家长)的记录进行排序,然后他们的孩子应该在之后出现,例如C# 带扭曲的Linq排序,c#,performance,linq,C#,Performance,Linq,我有以下记录 最后2个是记录3和4的子项,我希望能够按数量对记录进行排序,但应该是先对非兴趣(家长)的记录进行排序,然后他们的孩子应该在之后出现,例如 2000 2000 20001 99.84 (child of the above) 50000 249.58 (child of the above) 基本上,我希望我的排序数量忽略“IsInterest”设置为true的那一个,但让它们出现在它们的父母之后 我可以先把所有的父母都带到一个新的收藏中去。。然后通过父项查看是否有子项,然后将它
2000
2000
20001
99.84 (child of the above)
50000
249.58 (child of the above)
基本上,我希望我的排序数量忽略“IsInterest”设置为true的那一个,但让它们出现在它们的父母之后
我可以先把所有的父母都带到一个新的收藏中去。。然后通过父项查看是否有子项,然后将它们插入新集合中的父项之后,但我觉得这不是有效且肮脏的代码,所以我想我会问可能有人知道黑魔法。
分拣员还应了解金额上的asc/desc
如果有帮助的话,我可以发布我的代码,把收藏拆开并放在一起,但如果可能的话,我会尽量不使用这些代码
我的排序方法使用字符串表示“升序”或“降序”,如果这样有帮助的话
多谢各位
更新2
我要指出的是,只有两个级别,孩子们只有一个父母(没有祖父母),每个父母最多有一个孩子
根据请求更新代码(字段名称可能不同于数据库字段..)
public static IOrderedEnumerable<TSource> OrderByWithDirection<TSource, TKey>(this IEnumerable<TSource> source, Func<TSource, TKey> keySelector, bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
public static IOrderedQueryable<TSource> OrderByWithDirection<TSource, TKey>(this IQueryable<TSource> source, Expression<Func<TSource, TKey>> keySelector, bool descending)
{
return descending ? source.OrderByDescending(keySelector)
: source.OrderBy(keySelector);
}
public static IOrderedEnumerable OrderByWithDirection(此IEnumerable源代码,Func键选择器,布尔递减)
{
返回降序?source.OrderByDescending(keySelector)
:source.OrderBy(keySelector);
}
公共静态IOrderedQueryable OrderByWithDirection(此IQueryable源、表达式键选择器、布尔降序)
{
返回降序?source.OrderByDescending(keySelector)
:source.OrderBy(keySelector);
}
这里有一个简单的Linq解决方案:
var desc = order == "descending";
var result = list
//group parents with it's children
.GroupBy(x => x.ParentId ?? x.Id)
//move the parent to the first position in each group
.Select(g => g.OrderBy(x => x.ParentId.HasValue).ThenBy(x => desc ? -x.Amount : x.Amount))
//sort the groups by parents' amounts
.OrderBy(g => desc ? -g.First().Amount : g.First().Amount)
//retrieve the items from each group
.SelectMany(g => g);
一些性能提示:
- 如果总是最多有一个孩子,或者您不关心孩子的顺序,那么您可以先删除
,然后再删除(…)
- 使用
语句检查顺序,并有两个版本的语句-第二个版本使用if
/OrderByDescending
,并删除三元运算符(然后使用bydescending
)-否则将对每个项目求值desc?…:
我不会就您当前的解决方案的性能提供任何保证-它可能会变得更慢。您可以使用以下通用方法(不受级别或父/子级数量的限制): 更新:事实证明,事情并不是那么简单。虽然上面的方法为叶元素以及元素对其父元素提供了正确的顺序,但它不能正确地对父元素进行排序。正确的方法如下(从这里使用另一个可重用方法,因此如果我们不计算它实际上并不比前面的方法大多少):
向我们展示您当前的排序方法。您可以在
OrderBy
/OrderByDescending
之后使用ThenBy
/OrderByDescending
进行排序。您将如何做到这一点,它将第一次对它们进行排序,99.83249.582000。。。。。这不是我想在这个网站上得到的帮助,你应该遵守它的规则/期望。也就是说:按照Ivan的建议,首先自己尝试一下,让我们看看你做了什么。在任何情况下,我已经说了所有你需要知道的:使用LINQ,你可以通过使用然后使用/然后使用Descending
@IvanStoev code postedas在主线程中更新,迭代地重新排序(首先根据特定的条件,然后根据不同的条件,等等),只会有一个子项,而且只有一代人(只有父母有一个孩子)不涉及祖父母
var desc = order == "descending";
var result = list
//group parents with it's children
.GroupBy(x => x.ParentId ?? x.Id)
//move the parent to the first position in each group
.Select(g => g.OrderBy(x => x.ParentId.HasValue).ThenBy(x => desc ? -x.Amount : x.Amount))
//sort the groups by parents' amounts
.OrderBy(g => desc ? -g.First().Amount : g.First().Amount)
//retrieve the items from each group
.SelectMany(g => g);
public static class Extensions
{
public static IEnumerable<T> ThenByHierarchy<T, TKey>(this IOrderedEnumerable<T> source, Func<T, TKey> keySelector, Func<T, TKey> parentKeySelector)
{
var itemByKey = source.ToDictionary(keySelector);
var processSet = new HashSet<T>();
var stack = new Stack<T>();
foreach (var item in itemByKey.Values)
{
for (var next = item; processSet.Add(next); )
{
stack.Push(next);
if (!itemByKey.TryGetValue(parentKeySelector(next), out next)) break;
}
while (stack.Count != 0)
yield return stack.Pop();
}
}
}
var result = contributions
.OrderByWithDirection(x => x.ContributionAmount, sortDirection.ToUpper() == "DESCENDING")
.ThenByHierarchy(x => x.ContributionId, x => x.ParentContirbutionId);
public static class Extensions
{
public static IEnumerable<T> HierarchicalOrder<T, TKey>(this IEnumerable<T> source, Func<T, TKey> keySelector, Func<T, TKey> parentKeySelector, Func<IEnumerable<T>, IOrderedEnumerable<T>> order)
{
// Collect parent/child relation info
var itemById = source.ToDictionary(keySelector);
var childListById = new Dictionary<TKey, List<T>>();
var rootList = new List<T>();
foreach (var item in itemById.Values)
{
var parentKey = parentKeySelector(item);
List<T> childList;
if (parentKey == null || !itemById.ContainsKey(parentKey))
childList = rootList;
else if (!childListById.TryGetValue(parentKey, out childList))
childListById.Add(parentKey, childList = new List<T>());
childList.Add(item);
}
// Traverse the tree using in-order DFT and applying the sort on each sublist
return order(rootList).Expand(item =>
{
List<T> childList;
return childListById.TryGetValue(keySelector(item), out childList) ? order(childList) : null;
});
}
public static IEnumerable<T> Expand<T>(this IEnumerable<T> source, Func<T, IEnumerable<T>> elementSelector)
{
var stack = new Stack<IEnumerator<T>>();
var e = source.GetEnumerator();
try
{
while (true)
{
while (e.MoveNext())
{
var item = e.Current;
yield return item;
var elements = elementSelector(item);
if (elements == null) continue;
stack.Push(e);
e = elements.GetEnumerator();
}
if (stack.Count == 0) break;
e.Dispose();
e = stack.Pop();
}
}
finally
{
e.Dispose();
while (stack.Count != 0) stack.Pop().Dispose();
}
}
}
var result = contributions
.HierarchicalOrder(x => x.ContributionId, x => x.ParentContirbutionId, c =>
.OrderByWithDirection(x => x.ContributionAmount, sortDirection.ToUpper() == "DESCENDING"));