【问题标题】:Customizing Sort Order of C# Arrays自定义 C# 数组的排序顺序
【发布时间】:2009-06-24 09:45:18
【问题描述】:

这已经困扰我一段时间了。我尝试了几种方法,但都没有正常工作。

我正在编写 IRC 客户端,正在尝试整理用户名列表(需要按当前频道中用户的访问级别进行排序)。

这很容易。麻烦的是,每当用户加入或离开频道时,都需要添加此列表,因此他们的用户名必须在离开时删除列表,并在他们重新加入时重新添加到正确的位置。

每个用户的访问级别由每个用户名开头的单个字符表示。这些字符是保留的,因此不存在以其中一个符号开头的名称的潜在问题。从最高到最低的符号(按我需要排序的顺序)是: ~ & @ % +

没有任何访问权限的用户在其用户名前没有符号。它们应该位于列表的底部。

例如:未排序的数组可能包含以下内容: ~user1 ~user84 @user3 &user8 +user39 user002 user2838 %user29

并且需要进行排序,以便元素按以下顺序排列: ~user1 ~user84 &user8 @user3 %user29 +user39 user002 user2838

用户按访问级别排序后,还需要按字母顺序排序。

在这里问是最后的手段,如果有人可以帮助我,我将非常感激。 提前谢谢你。

【问题讨论】:

  • 您如何存储用户名列表?如果它是一个数据库,那么您可以在将数据放入列表之前使用 SQL 以您想要的顺序检索数据吗?

标签: c# arrays sorting irc


【解决方案1】:

只要数组包含一个对象,然后在对象上实现IComparable,然后调用Array.Sort()。

如果集合是可变的,我建议使用列表。

【讨论】:

  • 可能最好使用 IComparable 而不是非泛型 IComparable,或者继承实现两者的 Comparable
  • 是的,如果 OP 使用 List,IComparable 会很好,但我认为这不适用于需要 IComparable 的 Array.Sort()。
【解决方案2】:

您可以使用SortedList<K,V> 和K(键)实现IComparable 接口,然后定义您的排序标准。 V 可以简​​单地为 null 或相同的 K 对象。

【讨论】:

  • 他希望对值进行排序,而不是对键进行排序……这似乎是一种非常非常迂回的做法。
  • 不是真的 - 在这种情况下键 == 值。如果你已经有一个排序列表,那么每次添加元素时调用 Sort() 是非常低效的。无论如何,如果你想要一个更干净的解决方案,你可以使用 PowerCollections 的 OrderedSet,例如 (codeplex.com/PowerCollections)
【解决方案3】:

您可以将IComparer<T>Comparison<T> 发送给Array.Sort。然后你只需要自己实现比较。如果这是一个相对复杂的比较(听起来像这样),我会在一个单独的类中实现IComparer<T>,您可以轻松地对其进行单元测试。然后调用:

Array.Sort(userNames, new UserNameComparer());

如果 UserNameComparer 没有状态,您可能希望定义一个方便的实例:

Array.Sort(userNames, UserNameComparer.Instance);

List<T> 有类似的排序选项 - 如果您要定期添加/删除项目,我个人会使用列表而不是数组。

事实上,听起来您并不经常需要真正进行完整排序。删除用户不会更改排序顺序,插入仅意味着在正确的位置插入。换句话说,你需要:

  • 创建列表并对其进行排序以开始
  • 删除用户只是一个简单的操作
  • 添加用户需要找出插入用户的位置

您可以使用Array.BinarySearchList.BinarySearch 执行最后一步,这再次允许您指定自定义IComparer<T>。一旦你知道在哪里插入用户,你就可以相对便宜地做到这一点(与再次对整个集合进行排序相比)。

【讨论】:

    【解决方案4】:

    你应该看看IComparer 接口(或者它是generic version)。在实现CompareTo 方法时,检查两个用户名中的任何一个是否包含您的保留字符之一。如果两者都没有特殊的保留字符或两者都具有相同的字符,则调用String.CompareTo 方法,该方法将处理字母排序。否则使用您的自定义排序逻辑。

    【讨论】:

      【解决方案5】:

      我试了一下排序,想出了以下排序方法:

      List<char> levelChars = new List<char>();
      levelChars.AddRange("+%@&~".ToCharArray());
      List<string> names = new List<string>();
      names.AddRange(new[]{"~user1", "~user84",  "@user3", "&user8", "+user39", "user002", "user2838", "%user29"});
      names.Sort((x,y) =>
                     {
                         int xLevel = levelChars.IndexOf(x[0]);
                         int yLevel = levelChars.IndexOf(y[0]);
      
                         if (xLevel != yLevel)
                         {
                             // if xLevel is higher; x should come before y
                             return xLevel > yLevel ? -1 : 1;
                         }
      
                         // x and y have the same level; regular string comparison
                         // will do the job
                         return x.CompareTo(y);                       
                     });
      

      这个比较代码也可以存在于IComparer&lt;T&gt; 实现的Compare 方法中。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2010-10-23
        • 1970-01-01
        • 2019-08-20
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2015-05-12
        相关资源
        最近更新 更多