2

我有一堂课,就像学生坐的那样。我有像 B6 B7 B8 B9 B10 B11 这样的位置,如果我在某些类中使用 FindAll(一个 oops 版本),我会按照这个顺序得到它,一切都很好,直到我这样做

    someclass.OrderBy(r => r.location);

在该位置变为 B10 B11 B6 B7 B8 B9 之后,这里出了什么问题。那时我不使用 orderBY 会更好,但有人能告诉我我遇到问题的原因吗?

4

8 回答 8

4

您可以实现自己的自定义比较器...

class CustomCompare : IComparer<string>
{
    private static readonly char[] _digits = "0123456789".ToArray();

    public int Compare(string a, string b)
    {
        //assuming alpha start, numeric end
        var alphaA = a.TrimEnd(_digits);
        var alphaB = b.TrimEnd(_digits);
        var alphaCompareTo = alphaA.CompareTo(alphaB);

        if (alphaCompareTo != 0)
        {
            return alphaCompareTo;
        }

        var numericA = int.Parse(a.Substring(alphaA.Length));
        var numericB = int.Parse(b.Substring(alphaB.Length));

        return numericA.CompareTo(numericB);
    }
}

...并像这样使用它...

someclass.OrderBy(r => r.location, new CustomCompare());
于 2013-01-29T15:44:34.580 回答
3

这是因为字符串被比较为......嗯,字符串。 '1'小于'6',因此词法比较将在该字符处停止。

听起来您想要自然排序而不是词汇排序。

于 2013-01-29T15:33:41.167 回答
3

我想你的location属性(或字段)是一个字符串?

你可以一个Comparer<>like:

sealed class LocationComparer : Comparer<string>
{
  // expect strings like "B3" or "C26"
  public override int Compare(string x, string y)
  {
    int result = x[0].CompareTo(y[0]);
    if (result != 0)
      return result;
    result = ushort.Parse(x.Substring(1)).CompareTo(ushort.Parse(y.Substring(1)));
    return result;
  }
}

像使用它sorted = someclass.OrderBy(r => r.location, new LocationComparer());

或者您可以将您的类型更改为location以下样式的类:

// this class inherits the IComparable implementation of Tuple`2
sealed class Location : Tuple<char, ushort>
{
  public Location(char letter, ushort number)
    : base(char.ToUpper(letter), number)
  {
  }

  public Location(string locationString)
    : this(letter: locationString[0], number: ushort.Parse(locationString.Substring(1)))
  {
  }

  public override string ToString()
  {
    return Item1.ToString() + Item2.ToString();
  }
}

Someclass类里面location有类型Location。然后你的原件sorted = someclass.OrderBy(r => r.location);就可以了。

两种解决方案都只是草图。我猜你会想要添加一些健全性检查。

于 2013-01-29T16:05:22.097 回答
2

Order by 使用字符串排序,而不是数字排序。

'B10' < 'B6'

逐个字符地比较每个条目:

'B10'
'B6'
  ^

这是重要的字符(因为 B 是相同的)。“6”>“1”。

于 2013-01-29T15:32:57.283 回答
1

orderby 工作正常,请注意字符串 B10 在字符串 B11 之前,而 B11 又在 B6 之前

请注意,您正在尝试订购一个List<string>(或者这就是我的想法)而不是List<int>

于 2013-01-29T15:33:51.103 回答
1

为了使字符串中的数字按字典顺序呈现,它们需要被填充,即 B01 < B06 < B10 因为 B6 是 > B10,因为它是从左到右完成的。因此,如果您知道上限,您的简单选择是填充,否则您将不得不重新考虑一下。

于 2013-01-29T15:35:14.140 回答
0

它们总是采用“X###”的形式吗?如果是这样,您可以使用:

yourListObject.OrderBy(r => int.Parse(r.location.SubString(1)));

这是一种解决方法。如果情况要复杂得多,那么您还需要为新创建的 Location 类创建一个比较器对象。

于 2013-01-29T15:42:58.870 回答
0

你需要一个自然的排序算法。从伊恩那里拿走这个并称之为:

someclass.OrderBy(r => r.location, new EnumerableComparer<String>());
于 2013-01-29T15:46:26.897 回答