【问题标题】:Is there a sorted collection type in .NET?.NET 中有排序的集合类型吗?
【发布时间】:2010-09-16 19:50:19
【问题描述】:

我正在寻找一个能够将所有物品保持井井有条的容器。我查看了 SortedList,但这需要一个单独的键,并且不允许重复键。我也可以只使用一个未排序的容器,并在每次插入后对其进行显式排序。

用法:

  • 偶尔插入
  • 按顺序频繁遍历
  • 最好不要使用与实际对象分开的键,而是使用比较函数进行排序。
  • 需要对等效对象进行稳定排序,但不是必需的。
  • 不需要随机访问。

我意识到我可以自己构建一个平衡的树结构,我只是想知道框架是否已经包含这样的野兽。

【问题讨论】:

    标签: c# .net sorting containers


    【解决方案1】:

    您可能想看看Wintellect Power Collections。它在 CodePlex 上可用,并且包含很多非常有用的集合。项目中的 OrderedBag 集合正是您要寻找的。它本质上使用red-black tree 来提供非常有效的排序。

    【讨论】:

    • 用鲍勃·迪伦(Bob Dylan)的不朽名言……时代在变。所以我只想补充一点,SortedSet 现在是 4.0 框架的一部分。 SortedSet 也被实现为红黑树。
    • @EBarr:你应该发布这个作为答案,我差点错过你的评论!必须知道我们现在有一个内置选项。
    • 开启者想要插入等价的对象,所以 SortedSet 不能作为一个选项。
    【解决方案2】:

    只是为了让EBarr's comment 作为答案,从.NET 4.0 开始就有SortedSet<T>。当然它是一个集合,这意味着你不能有重复。

    【讨论】:

    • 由于他没兴趣回答,而且很容易错过cmets,所以我努力了..
    • 我需要对 INT 主键进行排序查找,而 SortedSet<t> 工作得很好,因为这些值已经保证是唯一的。 +1
    【解决方案3】:

    如果您只想坚持使用标准集合,那么 List<> 类的 Sort(IComparer<>) 函数是经常被忽略的函数。您需要做的就是为您的对象创建一个合适的Comparer<>。例如:

    public class PositionDateComparer : IComparer<VehiclePosition>
    {
        public int Compare(VehiclePosition x, VehiclePosition y)
        {
            if (x.DateTime == DateTime.MinValue)
            {
                if (y.DateTime == DateTime.MinValue)
                {
                    // If x is null and y is null, they're
                    // equal. 
                    return 0;
                }
    
                // If x is null and y is not null, y
                // is greater. 
                return -1;
            }
    
            // If x is not null...
            //
            if (y.DateTime == DateTime.MinValue)
            // ...and y is null, x is greater.
            {
                return 1;
            }
    
            // ...and y is not null, compare the dates
            //
            if (x.DateTime == y.DateTime)
            {
                // x and y are equal
                return 0;
            }
    
            if (x.DateTime > y.DateTime)
            {
                // x is greater
                return 1;
            }
    
            // y is greater
            return -1;
        }
    }
    

    然后,只要您想在访问列表之前对列表进行排序,只需执行vehiclePositionsList.Sort(new PositionDateComparer())。我意识到这可能不像每次添加新对象时都会自动排序的容器那么简单,但对于许多人(比如我!)来说,这可能足以成功完成这项工作而无需任何额外的库。

    【讨论】:

      【解决方案4】:

      我会扩展您自己的列表类,正如您所提到的,它只是在每次插入之后进行排序。由于您的插入不频繁,因此对性能的影响很小,并且无论如何对几乎排序的列表进行排序是很快的。扩展通用列表并覆盖 Add 方法以立即排序。如果性能成为问题,您可以插入到位以节省一些时间。此外,您可以对插入进行排队,以便对要插入的所有值进行一次遍历插入。

      【讨论】:

      • 对于 Add(),您可能需要尝试 BinarySearch 以找到正确的位置,然后执行 Insert()。您还需要覆盖 AddRange(),尽管您可能希望将所有内容添加到末尾并进行单一排序。此外,您需要覆盖然后禁用 Insert() 和 InsertRange() 以防止无意中“取消排序”集合。
      【解决方案5】:

      正如我今天早些时候提到的hereC5 Generic Collection Library 有适合您的容器。

      【讨论】:

      • 那么哪个集合是答案?
      • 查阅文档,TreeBag&lt;T&gt;(SCG.IComparer&lt;T&gt; cmp) 应该满足操作要求。
      【解决方案6】:

      如果键也是对象的属性,你可以试试System.Collections.ObjectModel.KeyedCollection&lt;TKey, TItem&gt;。它是一个抽象类,但如果您的密钥只是项目的一个属性,那么它的派生非常简单。

      【讨论】:

      • 这更接近,但同样需要唯一的键。我可能只需要添加一个计数器来保持它们的唯一性。
      • 此外,这只是一个尊重集合的顺序,而不是我认为 OP 所追求的始终排序的集合。
      • 如果您不使用 TItem 作为查找值,则始终可以将 TKey 设为值,将 TItem 设为计数器。
      【解决方案7】:

      这是我在 VB6 中用来按字母顺序排序的一个老技巧:使用 System.Windows.Forms ListBox 对象,并将其“Sorted”属性设置为 true。在 C# 中,您可以将任何对象插入到列表框中,它会根据对象的 ToString() 值按字母顺序对对象进行排序:

      对于一个类模块:


      使用 System.Windows.Forms;

          static void Main(string[] args)
          {
              ListBox sortedList = new ListBox();
              sortedList.Sorted = true;
      
              sortedList.Items.Add("foo");
              sortedList.Items.Add("bar");
              sortedList.Items.Add(true);
              sortedList.Items.Add(432); 
      
              foreach (object o in sortedList.Items)
              {
                  Console.WriteLine(o);
              }
      
              Console.ReadKey();
          }
      

      这将显示:

      432
      酒吧

      真的

      【讨论】:

      • ...我会和VB6一起给它一个体面的埋葬
      • List 也可以做到这一点,而且不需要表单控件(它有一个 Sort() 方法)。创建一个表单控件来做一个简单的排序操作不仅是一种矫枉过正,而且完全没用。这个答案完全忽略了OP的非常详细和明确的问题。如果您了解为什么此答案无法帮助任何寻找所提出问题的解决方案的人,您可以将其删除并恢复您失去的声誉。
      猜你喜欢
      • 2011-09-23
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-14
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多