【问题标题】:how to sort a list then sort a subset of that list如何对列表进行排序,然后对该列表的子集进行排序
【发布时间】:2014-03-18 11:38:33
【问题描述】:

我有一组线条。每行都是字段的集合。很容易找到第 1 列并按其内容排序:

_lines = lines.OrderBy(l => l.Fields.Find(f => f.ColumnNumber == 1).Content).ToList();

但是我如何对这个列表的一个子集进行排序呢?我想按 f.ColumnNumber == 3 排序,其中 (f.ColumnNumber == 1).Content 为 6。

所以我的线条集合看起来像这样:

Col1, Col2, Col3

1, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data, data

我想按 col1 排序,然后只排序 col1 == 6 的 col1,但按 col3 排序。

有没有办法在 c# 中做到这一点?我似乎找不到神奇的公式。

编辑:

我的示例数据有点过于简化了。有些行有 3 列,其他行有更多或更少的列。因此,当我使用 .ThenBy 扩展时,如果我试图对 col 3 上的行进行子排序但说第 9 行只有一列,我会得到一个对象引用,它没有设置为对象异常的实例。

这是一个更好的示例数据示例:

Col1, Col2, Col3, Col4

1, data, data, data
5, data, data
6, data, Chuck
6, data, Chuck
6, data, Jeffster
6, data, Jeffster
6, data, Grunke
6, data, Gertrude
8, data, data
9, data

Code 1 lines have 4 columns.
Code 5 lines have 3.
Code 6 lines have 3 - and I need to sort by col 3 alphabetically.
Code 8 lines have 3 columns.
Code 9 lines have 2.

无法保证列表完全排序。所以我首先需要按第一列 1-9 对行进行排序,然后我只需要按列 3 对代码 6 进行排序。

编辑 2:

我的类结构有点复杂,所以我尽量保持简单,希望它就足够了,但看起来他的情况并非如此,所以让我与你分享一下类定义:

public class Field : IField
{
    public FieldSpecification Specification { get; set; }
    public string Content { get; set; }
}

public class FieldSpecification
{
        public int ColumnNumber { get; set; }
        public int Length { get; set; }
        public int StartPosition { get; set; }
        public int EndPosition { get { return StartPosition + Length - 1; } }
        public Justification Justification { get; set; }
        public char PadCharacter { get; set; }
}

那我有一堆符合ILine接口的行

public interface ILine
{
    List<IField> Fields { get; set; }
    int Credits { get; }
    int Debits { get; }
    BigInteger Hash { get; }
}

所以从技术上讲,我在上面显示了类似 field.ColumnNumber,但它应该是 field.Specification.ColumnNumber。

目标是根据可以更改的规范构建固定宽度的文件。所以每一行都有一个带有规范的字段集合,然后数据可以进入内容,规范可以帮助做验证:格式化验证。

我希望有一种方法可以使用 linq 对列表子集进行排序,但我可能需要解构我的最终行集合,对其进行排序,然后重新构建集合。我希望避免这种情况。

【问题讨论】:

  • 请不要在问题标题中包含有关所用语言的信息,除非没有它就没有意义。标记用于此目的。
  • 谢谢 Ondrej。我以后一定会这样做的。
  • 我认为您不能通过让我们知道您的数据的类定义来帮助我们吗?
  • 那么,Fields 是什么类型的?
  • 不是您的问题,但是...我知道BigInteger 将有助于避免碰撞,但它永远不会像int 那样快。你不应该有一个快速的散列但准确的等号。

标签: c# linq list sorting


【解决方案1】:

您可以使用ThenBy 扩展名。

看看你想要的输出,看起来很简单,

 var output = lines.Select(l => new
    {
        Col1 =  int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
        Col2 =  l.Fields.Find(f => f.ColumnNumber == 2).Content,
        Col3 =  l.Fields.Find(f => f.ColumnNumber == 3).Content
    }).OrderBy(l => l.Col1).ThenBy(l => l.Col3);

足够了。


如果由于某种原因,您只想在Col16 时订购子列表,

 var output = lines.Select(l => new
    {
        Col1 =  int.Parse(l.Fields.Find(f => f.ColumnNumber == 1).Content),
        Col2 =  l.Fields.Find(f => f.ColumnNumber == 2).Content,
        Col3 =  l.Fields.Find(f => f.ColumnNumber == 3).Content
    }).OrderBy(l => l.Col1).ThenBy(l => l.Col1 == 6 ? l.Col3 : null);

最后一个警告,根据 Fields 的类型,可能有更好的方法来解决所有这些问题。

【讨论】:

  • 这将对所有子集进行排序,而不仅仅是他特别想要排序的子集。
  • 是的,这行得通,尽管我不确定OrderBy(x =&gt; null) 是否能保持秩序。另一种选择是按Col1 分组,然后在分组上使用SelectMany,如果满足谓词,则可以选择在每个组上调用OrderBy。诚然,您的解决方案更简洁。
【解决方案2】:

可以通过ThenBy扩展方法完成;一般来说,这个概念被称为lexicographical order

【讨论】:

    【解决方案3】:

    如果我可以假设你的类定义是这样的:

    public class Datum
    {
        public int ID { get; set; }
        public string[] Cols { get; set; }
    }
    

    然后我可以这样定义数据:

    var data = new []
    {
        new Datum() { ID = 1, Cols = new [] { "data", "data", "data", }, },
        new Datum() { ID = 5, Cols = new [] { "data", "data", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Chuck", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Jeffster", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Grunke", }, },
        new Datum() { ID = 6, Cols = new [] { "data", "Gertrude", }, },
        new Datum() { ID = 8, Cols = new [] { "data", "data", }, },
        new Datum() { ID = 9, Cols = new [] { "data", }, },
    };
    

    然后我可以这样排序:

    var sorted =
        from d in data
        let key =
            String.Format("{0:0000}", d.ID)
            + (d.ID != 6 ? "" : "-" + d.Cols[1])
        orderby key
        select d;
    

    我得到了这些结果:

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-06-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-21
      • 2012-12-16
      相关资源
      最近更新 更多