【问题标题】:How can I get OrderBy or IComparer to sort my particular list?如何让 OrderBy 或 IComparer 对我的特定列表进行排序?
【发布时间】:2018-09-17 15:01:45
【问题描述】:

字典 ints 我最初在 1 - 100 的范围内随机生成,使用:

var lstNumbers = Enumerable.Range(1, 100).OrderBy(n => Guid.NewGuid)
                           .GetHashCode()).ToList();

创建字典并用于将ColorType 值分配给列表中的所有数字,依次为 Red、Yellow、White、Red、Yellow、White 等的每个数字:

var startColor = ColorType.Red;
var map = new Dictionary<int, ColorType>();
foreach(var number in lstNumbers) {
  // First color for assignment
  map[number] = startColor.Next();
  // Go to the next color
  startColor = startColor.Next();
}

然后我用几种不同的方式删除项目:

foreach(KeyValuePair<int, ColorType> entry in map.ToList()) {
  if (entry.Key % 2 == 0 && entry.Value == ColorType.Red) {
    map.Remove(entry.Key);
  }
  if (entry.Key % 2 == 1 && entry.Value == ColorType.Yellow) {
    map.Remove(entry.Key);
  }
  if (entry.Key % 3 == 0 && entry.Value == ColorType.White) {
    map.Remove(entry.Key);
  }
}

然后我按升序对数字进行排序:

foreach(var number in map.OrderBy(i => i.Key)) {
  Console.WriteLine(number);
}

Console.ReadLine();

所以我的列表现在看起来差不多是这样的:

[53, Red]
[54, Yellow]
[55, White]
[56, Yellow]
[61, White]
[62, White]
[64, Yellow]
[65, Red]
ect., ect.

现在我需要按值对字典中的最终列表进行排序,白色结果在顶部,黄色在中间,红色在底部。红

我尝试了这个OrderBy,但我可能没有正确实现它,或者它可能不适用于我的场景,因为我收到错误:

== 运算符不能应用于 'ColorType' 和 'string' 的操作数。

foreach(var color in map.OrderBy(c => c.Value == "White" ? 0 : c.Value == "Yellow" ? 1 : 2)) {
  Console.WriteLine(color);
}

我尝试使用 IComparer,但遇到了问题,因为我在字典中使用了自定义类型,用于颜色:

public class CustomerComparer : IComparer<KeyValuePair<int, ColorType>> {
  private List<string> orderedColors = new List<string>() { "White", "Yellow", "Red" };

  public int Compare(KeyValuePair<int, ColorType> str1, KeyValuePair<int, ColorType> str2) {
    return orderedColors.IndexOf(str1.Value) - orderedColors.IndexOf(str2.Value);
  }
}

var sorted = map.OrderBy(x => x, new CustomerComparer());

foreach(var entry in sorted) {
  Console.WriteLine("{0}: {1}", entry.Key, entry.Value);
}
Console.ReadKey();

我猜有更好的方法可以做到这一点,另一种方法,或者我完全错过了一些东西。

【问题讨论】:

  • colors.OrderBy(c =&gt; c.Value != ColorType.White).ThenBy(c =&gt; c.Value != ColorType.Yellow).ThenBy(c =&gt; c.Value != ColorType.Red)怎么样
  • 哪个ColorType? ?它存在于几个库中。为其提供完整的资格。
  • 永远不要使用 guid 作为随机源; 保证是随机的;它保证是唯一的,并且这些是不同的属性。其次,除了平衡哈希表之外,切勿将哈希码用于任何事情。您在同一个表达式中有两个不好的做法。如果你想打乱一个列表,那么要么按 保证 随机排序,要么实现一个 shuffle。
  • @JusteasyStackAttacka:也许只是阅读stackoverflow.com/q/375351/18192?或者只使用 Leopold Bushkin 的 RandomSubset 类(来自 Jon Skeet 的 MoreLinq 库)。它被记录为以随机顺序提供结果,因此只需将大小设置为列表的长度。
  • 如果你需要一个伪随机数序列,那么只需写static IEnumerable&lt;double&gt; PseudorandomNumbers() { Random r = new Random(); while(true) yield return r.NextDouble(); },现在你可以说Enumerable.Range(1,100).Zip(PseudorandomNumbers(), (i, d) =&gt; new { i, d }).OrderBy(p=&gt;p.d).Select(p=&gt;p.i).ToList(),你就完成了。如果您需要加密强度随机性,请执行相同的操作,但使用无限的加密强度数字序列。

标签: c# .net sorting dictionary icomparer


【解决方案1】:

正如您收到的错误所示,您尝试将ColorTypeString 进行比较。你需要让两边一样,要么都是ColorType

foreach (var color in map.OrderBy(c => c.Value == ColorType.White ?
                                       0 : c.Value == ColorType.Yellow ? 1 : 2)) {
    Console.WriteLine(color);
}

或两者都有String。你说ColorType是自定义数据类型,所以不知道ToString()会不会返回颜色的名字:

foreach (var color in map.OrderBy(c => c.Value.ToString() == "White" ?
                                       0 : c.Value.ToString() == "Yellow" ? 1 : 2)) {
    Console.WriteLine(color);
}

例如,如果您使用 System.Drawing.Color 类,ToString() 将不起作用,因为它返回类似 Color [Red] 的内容。相反,您可以使用 Name 属性:

foreach (var color in map.OrderBy(c => c.Value.Name == "White" ?
                                       0 : c.Value.Name == "Yellow" ? 1 : 2)) {
    Console.WriteLine(color);
}

所以我不知道您的 ColorType 类是否具有返回颜色名称的类似属性,或者 ToString() 是否可以完成这项工作。

【讨论】:

  • 哇,好的,我在第一个代码块中看到了。我不应该使用字符串。感谢您指出了这一点!现在我只需要拆分两条 Writelines 的读出方式,以便有一条线将它们分开。我以为break; 会起作用,但它没有。
【解决方案2】:

我认为您在这里不需要自定义比较器。您可以使用.ThenBy 链接订购。

你可以写

 var sorted = map.OrderBy(c => c.Value != ColorType.White)
                .ThenBy(c => c.Value != ColorType.Yellow)
                .ThenBy(c => c.Value != ColorType.Red);

注意!= 运算符——您是按布尔值排序的,所以falsetrue 之前。

【讨论】:

  • 这是一个很好的几行解决方案,我已经投了赞成票。我应该指出,如果列表很大,我们可能会更有效地使初始键值根据其值自然排序,如@jdweng 提到的那样
猜你喜欢
  • 1970-01-01
  • 2015-01-08
  • 1970-01-01
  • 1970-01-01
  • 2015-06-16
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2010-11-02
相关资源
最近更新 更多