ToList()可以更改列表中项目的顺序吗?

时间:2018-01-11 10:59:07

标签: c# list

list1list2中的项目顺序可能不同时 list2 = list1.ToList()并且都属于List类型

5 个答案:

答案 0 :(得分:2)

如果list1的排序方式一致,那么list2将采用相同的顺序。

有可能list1是某种类型,它本身并不承诺每次枚举时都有相同的顺序,在这种情况下,两者可能会有所不同,但它是list1的枚举逻辑对此负责,而不是ToList()。 (list1的名称表明它本身就是一个列表,在这种情况下,订单肯定会是相同的。)

这里的一个答案已经包含了ToList()的一个实现的来源。它不是唯一存在的ToList()版本,并且corefx优化了比netfx更多的情况,但仍然是所有版本按照它们在枚举时提供它们的顺序生成列表。

另一个答案是文档中没有保证这一点,只能通过List<T>构造函数的重载描述来进行枚举(顺便说一下,ToList()的所有实现都使用的唯一构造函数。 1}}在所有情况下)。

但是,不会接受不承诺维持订单的ToList()更改。

考虑someSource.OrderBy(x => x.ID).ToList()的情况。在这种情况下(顺便提一下,是在corefx中优化的情况),如果ToList()可以更改顺序,则显然会删除OrderBy()的点。

好的,那么如果有人以一种不承诺维持秩序的方式改变了ToList(),又将OrderBy()视为特例呢? (毕竟,在一个版本中,由于性能原因,它已经是一个特例)。好吧,那仍然会说someSource.OrderBy(x => x.ID).Where(x => !x.Deleted).ToList()。总而言之,如果我们的ToList()版本没有维护顺序,我们就能够提出某种linq查询,其中查询的另一部分承诺给定订单ToList()的这种实现打破了整个查询的承诺。

因此,除非使用ParallelEnumerable,否则除非您使用AsOrdered(),否则禁止使用特殊套管来明确不承诺维护订单(ToList(),因为它有许多优点除非在并行处理方面确实有必要,否则不能维护订单)我们无法在不违反整个linq查询承诺的情况下对ToList()进行更改而不维护订单。

因此虽然{Server:nginx.access.remote.count(1m,{Server:nginx.access.remote.last()},eq)}>10000的文档中没有提及保证,但它仍然有保证,不会在以后的版本中更改。

答案 1 :(得分:1)

简单的答案是否定的,ToList将循环遍历可枚举的源并保持相同的顺序。 List<T>保证订单,因此在其上调用ToList不会改变它。

然而,更细致的答案是,您可能不会以List<T>开头,并且可能会更加一般IEnumerable<T>,但根本不保证订单。这意味着多次调用{{1} } 可能产生不同的输出。

但实际上,source.ToList()的所有实现都会保留顺序。

答案 2 :(得分:1)

对于初学者:可以说每个人都希望这样做。但为什么呢?

根据文档,采用List<T>的{​​{1}}构造函数保证订单被保留:

  

元素按照集合枚举器读取的顺序复制到List上。

虽然IEnumerable<T>的文档没有做出这样的承诺(尽管如此,并没有说任何相反的事情)。

在内部,一个使用另一个,因此您是安全的,但如果.ToList()的内部实施发生变化,则无法保证您的安全。因此,如果您想确定,请直接致电.ToList()

Smallprint:如果你对它很挑剔......我找不到保证new List(oldList);接口按顺序返回列表的元素。所以两种方式,你必须看看是什么,如果你需要依赖它,也许可以编写一些单元测试来断言这种行为,这样你就可以在当前行为发生变化时立即得到通知。

答案 3 :(得分:1)

一般答案是,即使两个列表都是List的类型,也不会保留订单。

因为List不是密封类。另一个类可以从它派生并覆盖GetEnumerable并可能无序地返回项目。

听起来很奇怪,是的。但它可能。所以你不能说ToList将返回完全相同的列表,除非它们都是List的具体类型而不是任何派生类型。

另一个答案是它的实施细节可能在未来发生变化。我不这么认为。列表是.net集合中非常重要的一部分。这种无法改变的突破性变化非常不可取。

别担心,只要你使用具体的List订单始终保留。

答案 4 :(得分:0)

应该没有什么不同。检查源代码。

public static List<TSource> ToList<TSource>(this IEnumerable<TSource> source) {
    if (source == null) throw Error.ArgumentNull("source");
    return new List<TSource>(source);
}

创建列表时的部分

    // Constructs a List, copying the contents of the given collection. The
    // size and capacity of the new list will both be equal to the size of the
    // given collection.
    // 
    public List(IEnumerable<T> collection) {
        if (collection==null)
            ThrowHelper.ThrowArgumentNullException(ExceptionArgument.collection);
        Contract.EndContractBlock();

        ICollection<T> c = collection as ICollection<T>;
        if( c != null) {
            int count = c.Count;
            if (count == 0)
            {
                _items = _emptyArray;
            }
            else {
                _items = new T[count];
                c.CopyTo(_items, 0);
                _size = count;
            }
        }    
        else {                
            _size = 0;
            _items = _emptyArray;
            // This enumerable could be empty.  Let Add allocate a new array, if needed.
            // Note it will also go to _defaultCapacity first, not 1, then 2, etc.

            using(IEnumerator<T> en = collection.GetEnumerator()) {
                while(en.MoveNext()) {
                    Add(en.Current);                                    
                }
            }
        }
    }

https://github.com/Microsoft/referencesource/blob/master/System.Core/System/Linq/Enumerable.cs