如何通过linq对集合进行排序

本文关键字:排序 集合 何通过 linq | 更新日期: 2023-09-27 18:16:20

var ids = new int[] { 3, 2, 20, 1 };
var entities = categories.Where(entity => ids.Contains(entity.Id));

我必须像在ids数组中一样对实体进行排序。

如何通过linq对集合进行排序

这应该可以做到(写在我的脑海中,所以可能有错误)

var ids = new int[] { 3, 2, 20, 1 };
var ordering = ids.Select((id,index) => new {id,index});
var entities = 
    categories
        .Where(entity => ids.Contains(entity.Id))
        .AsEnumerable() //line not necessary if 'categories' is a local sequence
        .Join(ordering, ent => ent.Id, ord => ord.id, (ent,ord) => new {ent,ord})
        .OrderBy(x => x.ord.index)
        .Select(x => x.ent)

您可以使用OrderBy作为ids中id的索引。

要从ids中获得Id的索引,可以创建Id到索引的映射。这样,您可以在几乎恒定的时间内查找索引,而不必每次调用IndexOf并遍历整个列表。

像这样:

var idToIndexMap = ids
    .Select((i, v) => new { Index = i, Value = v })
    .ToDictionary(
        pair => pair.i,
        pair => pair.v
        );
var sortedEntities = categories
    .Where(e => ids.Contains(e.Id))
    .ToList() // Isn't necessary if this is Linq-to-Objects instead of entities...
    .OrderBy(e => idToIndexMap[e.Id])
    ;

你可以试试这个:

public class Foo
{
    public void Bar()
    {
        int[] idOrder = new int[] { 3, 2, 20, 1 };
        var lookup = idOrder.ToDictionary(i => i,
            i => Array.IndexOf(idOrder, i));
        foreach(var a in idOrder.OrderBy(i => new ByArrayComparable<int>(lookup, i)))
            Console.WriteLine(a);
    }
}
public class ByArrayComparable<T> : IComparable<ByArrayComparable<T>> where T : IComparable<T>
{
    public readonly IDictionary<T, int> order;
    public readonly T element;
    public ByArrayComparable(IDictionary<T, int> order, T element)
    {
        this.order = order;
        this.element = element;
    }
    public int CompareTo(ByArrayComparable<T> other)
    {
        return this.order[this.element].CompareTo(this.order[other.element]);
    }
}

这只适用于唯一元素,但查找工作量是恒定的。