C# 迭代列表的最快方法<;T>;按照int[]定义的顺序

C# 迭代列表的最快方法<;T>;按照int[]定义的顺序,c#,sorting,iteration,C#,Sorting,Iteration,什么是迭代元素列表的最快方法,其中每个项目都有一个关联的“分数”,分数最高的项目排在第一位 例如: List<X> items = new List<X>(new X[]{a,b,c,d}); int[] score = new int[]{20,301,-34,7}; foreach(X x in IterateByScore(items,score)) { // <-- Fastest way to do this? // order should be

什么是迭代元素列表的最快方法,其中每个项目都有一个关联的“分数”,分数最高的项目排在第一位

例如:

List<X> items = new List<X>(new X[]{a,b,c,d});
int[] score = new int[]{20,301,-34,7};
foreach(X x in IterateByScore(items,score)) { // <-- Fastest way to do this?
    // order should be b - a - d - c
}
List items=新列表(新X[]{a,b,c,d});
int[]分数=新的int[]{20301,-34,7};

foreach(IterateByScore(items,score)中的X){/注意:当第二个数组中的值是第一个数组中的索引时,此答案在问题更新之前发布

List
在内部使用数组,因此索引访问是最合理的选择:

foreach (int index in order)
{
    X x = items[index];
    ...
}
如果需要,可以将此间接索引逻辑封装到
IEnumerator
实现中,该实现将在其构造函数中接受
List
int[]
。这种方法在需要
IEnumerable
的情况下非常有用


(就我个人而言,我反对将重点放在性能上,除非这是您的程序中的一个性能瓶颈,我对此表示怀疑。)

虽然Ondrej的答案是正确的,但只有当您在列表上重复一次(或少量次)时,它才成立

如果需要多次迭代列表(按给定顺序),那么首先按所需顺序复制列表会更有效,因为这将提高缓存命中率并显著提高内存访问性能

List<X> items = new List<X>(new X[]{a,b,c,d});
int[] order = new int[] { 2, 3, 1, 0 };
List<X> sorted = order.Select(i => items[i]).ToList();

for (int i = 0; i < 10000000; ++i)
    foreach (X x in sorted)
    {
        // process x here
    }
List items=新列表(新X[]{a,b,c,d});
int[]顺序=新的int[]{2,3,1,0};
List sorted=order.Select(i=>items[i]).ToList();
对于(int i=0;i<10000000;++i)
foreach(X X已排序)
{
//这里是进程x
}

简单的解决方案是创建一个新类:

public class OrderedX
{
    public X Element { get; set; }
    public int Order { get; set; }
}
那就点吧

X[] element = new X[]{a,b,c,d});
int[] score = new int[]{20,301,-34,7};
List<OrderedX> items = new List<OrderedX>();
for (int i = 0; i < count; i++)
{
    items.Add(new OrderedX
    {
        X = element[i],
        Order = score[i]
    });
}
foreach(OrderedX x in items.OrderBy(a => a.Score)
{
    Process(x.X);
}
X[]元素=新的X[]{a,b,c,d});
int[]分数=新的int[]{20301,-34,7};
列表项=新列表();
for(int i=0;ia.Score)
{
过程(x.x);
}

对于更新后的问题,我假设最有效的方法是
数组。排序
方法:

List<X> items = new List<X>(new X[] { a, b, c, d });
int[] score = new int[] { 20, 301, -34, 7 };
List<X> sorted = items.ToArray();
Array.Sort(score, sorted);

foreach (X x in sorted)
{ 
    // process x here
}
List items=新列表(新X[]{a,b,c,d});
int[]分数=新的int[]{20,301,-34,7};
列表排序=items.ToArray();
Array.Sort(分数,排序);
foreach(X X已排序)
{ 
//这里是进程x
}
我可能会使用和匿名类型:

foreach (X x in items.Zip(scores, (item, score) => new { item, score })
                          .OrderByDescending(x => x.score).Select(x => x.item))
{
    // order is b - a - d - c
}

如果
X
与其分数的配对是常见的,则应创建一个命名类来代替该匿名类型。

是否有任何原因不能将排序值包含在“X”的定义中?@ChrisF:items和order来自代码的不同部分,它们应该分开保存。简单、容易,而且可能非常快。+1刚刚意识到我的示例过于简单了……我想问一些稍微不同的问题。无论如何,谢谢你的回答!@Danvil可能是我关于自定义
IEnumerator
implementa的更新tion是否指向了正确的方向?@Danvil这应该对您有用,因为您使用索引来指定顺序,这就是为什么您的示例很简单,如果您有其他方法来定义顺序(而不是基于索引)那么这个解决方案当然行不通了。@OndrejTucny:不太可能……但你的回答完全正确。我发布了一个新问题。应该有一个徽章,用于交叉编辑和交叉投票对方的答案:-)