C# 列表的多列并行排序<;T>;
对于C# 列表的多列并行排序<;T>;,c#,linq,sorting,parallel-processing,task-parallel-library,C#,Linq,Sorting,Parallel Processing,Task Parallel Library,对于列表,我需要实现多列排序,其中列名和排序方向在运行时是已知的。我使用了System.Linq.Dynamic OrderByAPI,它可以将列名和排序方向作为串联字符串,因此以下代码可以工作: List<T> data = DataCollection; // Stored in Cache var sortedData = data.OrderBy("Col1 asc, Col2 desc, Col3 asc,Col4 asc"); 问题: 有没有更好的方法实现同样的目标
列表
,我需要实现多列排序,其中列名和排序方向在运行时是已知的。我使用了System.Linq.Dynamic OrderBy
API,它可以将列名和排序方向作为串联字符串,因此以下代码可以工作:
List<T> data = DataCollection; // Stored in Cache
var sortedData = data.OrderBy("Col1 asc, Col2 desc, Col3 asc,Col4 asc");
问题:
- 有没有更好的方法实现同样的目标
- 对于integer来说,它很简单,如何翻译我的
多列排序的版本,因为选择分区将是一件复杂的事情
任何可以将我设置在正确路径上的指针最合乎逻辑的选择是从LINQ切换到 不幸的是,虽然
System.Linq.Dynamic
OrderBy
方法可以工作,但它实际上会命中可枚举
方法重载,因此对需要绑定到相应的可并行枚举
重载的并行查询
没有影响。另外,动态LINQOrderBy
实现使用内部类,因此不可能在外部扩展它(没有源代码)
仍然存在一个解决方案。您可以使用以下自定义扩展方法。它所做的是使用动态LINQ构建一个伪查询,然后使用相对简单的方法将与订单相关的Queryable
调用替换为相应的parallelenumable
方法:
然后比较性能。你试过PLINQ吗?我很想把它转移到一个有描述的数据库来管理索引和后续排序。@Ivan你是说AsParallel,这对linq动态多列排序有效吗,我没有试过如果你使用linq to sql,linq所做的就是将查询转发到sql Server。这就是所有处理将发生的地方,您的代码无法控制服务器如何进行排序。另一种方法是将所有数据放入一个
列表
,并使用某种并行排序——如果有PLINQ,则内置PLINQ,或者类似于您发布的内容。这是否比让服务器来做要快,这是一个悬而未决的问题。类似于mylist.AsParallel().OrderBy(s=>s.Col1)。然后by(s=>s.Col2)。然后by(s=>s.Col3)。然后by(s=>s.Col4)
work?非常好用,谢谢@Ivan,尽管我已经意识到在这个过程中,PLINQ做得同样好,非常感谢@Mrinal欢迎你,很高兴能帮助collegue(看到你在提问时感到有点奇怪:):),我确实充分利用了so的能力,提出了各种各样的问题,我不完全理解。在这个过程中,我得到了这么多好的解决方案,如果我用心去做,这可能是不可能的。充分利用社区的潜力。谢谢,如果计划发生变化,一定要主动伸出援助之手:)。
public class CustomSort
{
// Fetch Partition
public static int Partition(List<int> list, int left, int right)
{
int start = left;
int pivot = list[start];
left++;
right--;
while (true)
{
while (left <= right && list[left] <= pivot)
left++;
while (left <= right && list[right] > pivot)
right--;
if (left > right)
{
list[start] = list[left - 1];
list[left - 1] = pivot;
return left;
}
int temp = list[left];
list[left] = list[right];
list[right] = temp;
}
}
// Quick Sort serial
public static void QuickSort(List<int> list, int left, int right)
{
if (list == null || list.Count <= 1)
return;
if (left < right)
{
int pivotIdx = Partition(list, left, right);
QuickSort(list, left, pivotIdx - 1);
QuickSort(list, pivotIdx, right);
}
}
// Quick Sort Parallel
public static void QuickSortParallel(List<int> list, int left, int right)
{
if (list == null || list.Count <= 1)
return;
if (left < right)
{
int pivotIdx = Partition(list, left, right);
Task leftTask = Task.Run(() => QuickSort(list, left, pivotIdx - 1));
Task rightTask = Task.Run(() => QuickSort(list, pivotIdx, right));
Task.WaitAll(new[] { leftTask, rightTask });
}
}
}
public static class DynamicPLINQ
{
public static OrderedParallelQuery<T> OrderBy<T>(this ParallelQuery<T> source, string ordering, params object[] values)
{
var query = Enumerable.Empty<T>().AsQueryable();
var orderedQuery = query.OrderBy(ordering, values);
var binder = new ParallelQueryBinder();
binder.source = query;
binder.target = source;
var queryExpr = binder.Visit(orderedQuery.Expression);
return (OrderedParallelQuery<T>)query.Provider.Execute(queryExpr);
}
class ParallelQueryBinder : ExpressionVisitor
{
public object source;
public object target;
protected override Expression VisitConstant(ConstantExpression node)
{
if (node.Value == source)
return Expression.Constant(target);
return base.VisitConstant(node);
}
protected override Expression VisitUnary(UnaryExpression node)
{
if (node.NodeType == ExpressionType.Quote)
return Visit(node.Operand);
return base.VisitUnary(node);
}
static readonly string[] Methods = { "OrderBy", "OrderByDescending", "ThenBy", "ThenByDescending" };
protected override Expression VisitMethodCall(MethodCallExpression node)
{
if (node.Method.IsStatic && node.Method.DeclaringType == typeof(Queryable) && Methods.Contains(node.Method.Name))
{
var arguments = node.Arguments.Select(Visit).ToArray();
var result = Expression.Call(typeof(ParallelEnumerable), node.Method.Name, node.Method.GetGenericArguments(), arguments);
return result;
}
return base.VisitMethodCall(node);
}
}
}
var sortedData = data.AsParallel()
.OrderBy("Col1 asc, Col2 desc, Col3 asc,Col4 asc")
.ToList();