如何按顺序将项目插入列表?

Posted

技术标签:

【中文标题】如何按顺序将项目插入列表?【英文标题】:How to insert item into list in order? 【发布时间】:2012-08-23 17:20:34 【问题描述】:

我有一个DateTimeOffset 对象列表,我想按顺序将新对象插入到列表中。

List<DateTimeOffset> TimeList = ...
// determine the order before insert or add the new item

抱歉,需要更新我的问题。

List<customizedClass> ItemList = ...
//customizedClass contains DateTimeOffset object and other strings, int, etc.

ItemList.Sort();    // this won't work until set data comparison with DateTimeOffset
ItemList.OrderBy(); // this won't work until set data comparison with DateTimeOffset

另外,DateTimeOffset如何作为.OrderBy()的参数?

我也试过了:

ItemList = from s in ItemList
           orderby s.PublishDate descending    // .PublishDate is type DateTime
           select s;

但是,它会返回此错误消息,

无法将类型“System.Linq.IOrderedEnumerable”隐式转换为“System.Collections.Gerneric.List”。存在显式转换(您是否缺少演员表?)

【问题讨论】:

不能在需要时对列表进行排序或使用 SortedList 吗? List&lt;T&gt;ordered` 集合。你想*排序吗? 你在说什么“订单”? 我希望我的列表按 DateTimeOffset 排序 或者使用不同的集合类型,比如SortedBag&lt;T&gt;:is-there-a-sorted-collection-type-in-net 【参考方案1】:

假设您的列表已经按升序排序

var index = TimeList.BinarySearch(dateTimeOffset);
if (index < 0) index = ~index;
TimeList.Insert(index, dateTimeOffset);

【讨论】:

你能解释一下你的代码吗?如果他们不知道如何插入列表,我怀疑他们会知道~index 做了什么。 @AshBurlaczenko,你是对的,但问题的上下文似乎在我回答了约 1 小时后发生了变化,我懒得回答了。 来自 MSDN :返回值 排序 List 中项目的从零开始的索引,如果找到项目;否则,负数是下一个大于 item 的元素的索引的按位补码,如果没有更大的元素,则为 Count 的按位补码。【参考方案2】:

@L.B.'s answer 在边缘情况下的略微改进版本:

public static class ListExt

    public static void AddSorted<T>(this List<T> @this, T item) where T: IComparable<T>
    
        if (@this.Count == 0)
        
            @this.Add(item);
            return;
        
        if (@this[@this.Count-1].CompareTo(item) <= 0)
        
            @this.Add(item);
            return;
        
        if (@this[0].CompareTo(item) >= 0)
        
            @this.Insert(0, item);
            return;
        
        int index = @this.BinarySearch(item);
        if (index < 0) 
            index = ~index;
        @this.Insert(index, item);
    

【讨论】:

这个 sn-p 在我不能使用 SortedSet 并且不得不重复 .Sort() 一个 List 的情况下让我的性能提高了 1000%。 什么是@this @Baruch @this 是一个纯粹的常规变量名,通常用于引用被 C# 扩展方法扩展的对象。虽然 @this 是一个有效的 C# 变量名,但您可以使用其他任何名称,例如list 在这里可能有意义。 this 前面的@ 允许您使用保留字作为参数/变量,供以前没有遇到过的人使用。【参考方案3】:

使用 .NET 4,您可以使用新的 SortedSet&lt;T&gt;,否则您将无法使用键值集合 SortedList

SortedSet<DateTimeOffset> TimeList = new SortedSet<DateTimeOffset>();
// add DateTimeOffsets here, they will be sorted initially

注意:SortedSet&lt;T&gt; 类不接受重复元素。如果 item 已经在集合中,则此方法返回 false 并且不会抛出异常。

如果允许重复,您可以使用 List&lt;DateTimeOffset&gt; 并使用它的 Sort 方法。

【讨论】:

【参考方案4】:

修改你的 LINQ,在末尾添加 ToList():

ItemList = (from s in ItemList
            orderby s.PublishDate descending   
            select s).ToList();

或者将排序后的列表分配给另一个变量

var sortedList = from s in ....

【讨论】:

【参考方案5】:

我接受了@Noseratio's answer 并对其进行了重新设计,并将其与@Jeppe 来自here 的回答结合起来 获得一个适用于实现 IList 的集合的函数(我需要它用于路径的 ObservableCollection)和不实现 IComparable 的类型。

    /// <summary>
    /// Inserts a new value into a sorted collection.
    /// </summary>
    /// <typeparam name="T">The type of collection values, where the type implements IComparable of itself</typeparam>
    /// <param name="collection">The source collection</param>
    /// <param name="item">The item being inserted</param>
    public static void InsertSorted<T>(this IList<T> collection, T item)
        where T : IComparable<T>
    
        InsertSorted(collection, item, Comparer<T>.Create((x, y) => x.CompareTo(y)));
    

    /// <summary>
    /// Inserts a new value into a sorted collection.
    /// </summary>
    /// <typeparam name="T">The type of collection values</typeparam>
    /// <param name="collection">The source collection</param>
    /// <param name="item">The item being inserted</param>
    /// <param name="comparerFunction">An IComparer to comparer T values, e.g. Comparer&lt;T&gt;.Create((x, y) =&gt; (x.Property &lt; y.Property) ? -1 : (x.Property &gt; y.Property) ? 1 : 0)</param>
    public static void InsertSorted<T>(this IList<T> collection, T item, IComparer<T> comparerFunction)
    
        if (collection.Count == 0)
        
            // Simple add
            collection.Add(item);
        
        else if (comparerFunction.Compare(item, collection[collection.Count - 1]) >= 0)
        
            // Add to the end as the item being added is greater than the last item by comparison.
            collection.Add(item);
        
        else if (comparerFunction.Compare(item, collection[0]) <= 0)
        
            // Add to the front as the item being added is less than the first item by comparison.
            collection.Insert(0, item);
        
        else
        
            // Otherwise, search for the place to insert.
            int index = 0;
            if (collection is List<T> list)
            
                index = list.BinarySearch(item, comparerFunction);
            
            else if (collection is T[] arr)
            
                index = Array.BinarySearch(arr, item, comparerFunction);
            
            else
            
                for (int i = 0; i < collection.Count; i++)
                
                    if (comparerFunction.Compare(collection[i], item) <= 0)
                    
                        // If the item is the same or before, then the insertion point is here.
                        index = i;
                        break;
                    

                    // Otherwise loop. We're already tested the last element for greater than count.
                
            

            if (index < 0)
            
                // The zero-based index of item if item is found,
                // otherwise, a negative number that is the bitwise complement of the index of the next element that is larger than item or, if there is no larger element, the bitwise complement of Count.
                index = ~index;
            

            collection.Insert(index, item);
        
    

【讨论】:

collection.ToArray() 将创建另一个比线性搜索更昂贵的集合,即collection.IndexOf() 我在最后用新的处理方式进行了编辑——遗憾的是,Collection 没有二进制搜索,但是......嗯。【参考方案6】:

我很想对这里的两个建议进行基准测试,使用 SortedSet 类与基于列表的二进制搜索插入。从我在 .NET Core 3.1 上的(非科学)结果来看,对于小型(数百个)集合,List 似乎可能使用更少的内存,但是随着集合变得越大,SortedSet 在时间和内存上都开始获胜。

(项目是小类的实例,有两个字段,Guid id 和字符串名称)

50 项:

|        Method |     Mean |     Error |    StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------- |---------:|----------:|----------:|-------:|------:|------:|----------:|
|     SortedSet | 5.617 μs | 0.0183 μs | 0.0153 μs | 0.3052 |     - |     - |    1.9 KB |
| SortedAddList | 5.634 μs | 0.0144 μs | 0.0135 μs | 0.1755 |     - |     - |   1.12 KB |

200 项:

|        Method |     Mean |    Error |   StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------- |---------:|---------:|---------:|-------:|------:|------:|----------:|
|     SortedSet | 24.15 μs | 0.066 μs | 0.055 μs | 0.6409 |     - |     - |   4.11 KB |
| SortedAddList | 28.14 μs | 0.060 μs | 0.053 μs | 0.6714 |     - |     - |   4.16 KB |

1000 项:

|        Method |     Mean |   Error |  StdDev |  Gen 0 | Gen 1 | Gen 2 | Allocated |
|-------------- |---------:|--------:|--------:|-------:|------:|------:|----------:|
|     SortedSet | 107.5 μs | 0.34 μs | 0.30 μs | 0.7324 |     - |     - |   4.73 KB |
| SortedAddList | 169.1 μs | 0.41 μs | 0.39 μs | 2.4414 |     - |     - |  16.21 KB |

【讨论】:

【参考方案7】:

将项目插入特定索引

你可以使用:

DateTimeOffset dto;

 // Current time
 dto = DateTimeOffset.Now;

//This will insert the item at first position
TimeList.Insert(0,dto);

//This will insert the item at last position
TimeList.Add(dto);

要对集合进行排序,您可以使用 linq:

//This will sort the collection in ascending order
List<DateTimeOffset> SortedCollection=from dt in TimeList select dt order by dt;

【讨论】:

为什么不使用扩展名.OrderBy()进行排序 是的,Ash Burlaczenko 这也是我们可以做到的。我习惯在 linq 中编写大查询。这就是为什么我写了上面的查询,这是我想到的第一个想法。但我同意你的看法。谢谢。 List&lt;T&gt;.Add 没有采用索引的重载。我想你的意思是List&lt;T&gt;.Insert 是的,Daniel hilgarth,我的意思是 Insert(Index,object) 方法。谢谢 好问题,杰瑞。我不确定最好的方法。我认为这将取决于我们收集的数据。以及我们插入的日期。但是是的,BinarySearch 非常有效,您可以继续使用该集合或 SortedSet 集合。【参考方案8】:

很简单, 将数据添加到列表后

list.OrderBy(a => a.ColumnName).ToList();

【讨论】:

【参考方案9】:

找到你想要的索引后可以使用Insert(index,object)

【讨论】:

告诉我排序顺序以写更多

以上是关于如何按顺序将项目插入列表?的主要内容,如果未能解决你的问题,请参考以下文章

如何在插入点后不重新索引/移动项目的情况下将数据插入到有序、随机可访问的列表中?

如何在 Hive DB 框中的位置 0 处插入项目?

如何按字母顺序对项目进行排序?

Java二叉树按顺序插入

我如何测试使用硒在下拉菜单中按字母顺序对项目进行排序

如何按插入时间对 Meteor 集合进行排序?