LINQ方法基于更大的列表对列表进行排序

时间:2013-08-04 07:15:29

标签: c# linq sorting

List<int> _lstNeedToOrder = new List<int>();
_lstNeedToOrder.AddRange(new int[] { 1, 5, 6, 8 });

//I need to sort this based on the below list.

List<int> _lstOrdered = new List<int>();//to order by this list
_lstOrdered.AddRange(new int[] { 13, 5, 11, 1, 4, 9, 2, 7, 12, 10, 3, 8, 6 });

order will be -->_lstNeedToOrder = 5,1,8,6

我该怎么做?

6 个答案:

答案 0 :(得分:19)

简单 - 但效率低下 - 方式是:

var result = _lstNeedToOrder.OrderBy(x => _lstOrdered.IndexOf(x));

另一种方法是使用方法获得所需的值索引。如果您的值始终在[1 ... n]范围内,则可以将“有序”列表反转为“按值列出的索引列表”。此时你可以使用:

var result = _lstNeedToOrder.OrderBy(x => indexes[x]);

(其中indexes在0的开头有一个额外的值,只是为了让事情更简单。)

或者,您可以从值到索引创建Dictionary<int, int>。这将更加通用,因为它可以处理非常广泛的值而不需要占用大量内存。但是字典查找显然不如数组或列表查找效率高。

作为一个不能作为注释格式化的旁注,可以使用集合初始化器简化初始化:

var listToOrder = new List<int> { 1, 5, 6, 8 };
var orderedList = new List<int> { 13, 5, 11, 1, 4, 9, 2, 7, 12, 10, 3, 8, 6 };

答案 1 :(得分:13)

    List<int> results = _lstOrdered.Where(item => _lstNeedToOrder.Contains(item)).ToList();

答案 2 :(得分:4)

您可以构建这样的自定义比较器:

public class SequenceComparer<T> : IComparer<T> {
    private readonly Dictionary<T, int> indexes;

    public SequenceComparer(IEnumerable<T> sequence) {
        this.indexes =
            sequence
                .Select((item, index) => new { Item = item, Index = index })
                .ToDictionary(x => x.Item, x => x.Index);
    }

    public int Compare(T x, T y) {
        return indexes[x].CompareTo(indexes[y]);
    }
}

现在你可以说

var result = _lstNeedToOrder.OrderBy(x => x, new SequenceComparer(_lstOrdered));

答案 3 :(得分:4)

这很有效:

var lookup = _lstOrdered
    .Select((x, n) => new { x, n })
    .ToLookup(x => x.x, x => x.n);

var query =
    from x in _lstNeedToOrder
    let rank = lookup[x]
        .DefaultIfEmpty(int.MaxValue)
        .First()
    orderby rank
    select x;

答案 4 :(得分:2)

另一种选择是使用Intersect,它保证按照它们在第一个序列中出现的顺序返回元素。

所以,在这个例子中

var result = _lstOrdered.Intersect(_lstNeedToOrder);

根据需要产生{ 5, 1, 8, 6}

答案 5 :(得分:1)

在中间字典中保存订单......

// dict key will be the values of _lstOrdered, value will be the index of the
// key in _lstOrdered
// I'm using a seldom used .Select overload that returns the current value 
// plus its index (ix)
var dict = _lstOrdered.Select((p, ix) => new { Value = p, Ix = ix })
                      .ToDictionary(p => p.Value, p => p.Ix);

// note that this will explode if _lstNeedToOrder contains values outside
// _lstOrdered.
_lstNeedToOrder.Sort((p, q) => dict[p] - dict[q]);

.Sort方法就地排序,因此将订购_lstNeedToOrder。