32

我有一个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”。存在显式转换(您是否缺少演员表?)

4

9 回答 9

73

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

var index = TimeList.BinarySearch(dateTimeOffset);
if (index < 0) index = ~index;
TimeList.Insert(index, dateTimeOffset);
于 2012-08-29T06:59:11.017 回答
46

@LB对边缘情况的回答略有改进:

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);
    }
}
于 2014-04-02T04:04:54.927 回答
14

使用 .NET 4,您可以使用新的,SortedSet<T>否则您会被 key-value collection 困住SortedList

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

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

如果允许重复,您可以使用 aList<DateTimeOffset>并使用它的Sort方法。

于 2012-08-29T06:59:45.460 回答
4

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

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

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

var sortedList = from s in ....
于 2012-08-29T08:00:05.800 回答
3

我接受了@Noseratio 的答案并对其进行了重新设计并将其与@Jeppe 从这里的答案结合起来, 以获得一个适用于实现 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);
        }
    }
于 2017-07-06T11:32:52.713 回答
3

我很想对这里的两个建议进行基准测试,使用 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 |
于 2020-07-20T16:51:27.640 回答
1

将项目插入特定索引

您可以使用:

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;
于 2012-08-29T06:44:48.143 回答
1

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

list.OrderBy(a => a.ColumnName).ToList();
于 2017-06-07T12:05:24.343 回答
-2

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

于 2012-08-29T06:45:59.517 回答