如何对列表进行排序,然后对该列表的子集进行排序

时间:2014-03-18 11:38:33

标签: c# linq list sorting

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

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

但是,如何对此列表的子集进行排序?我想按f.ColumnNumber == 3排序,其中(f.ColumnNumber == 1)。内容为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,其中col1 == 6,但按col3排序。

有没有办法在c#中执行此操作?我似乎无法找到神奇的公式。

编辑:

我的示例数据略微简化了一些。有些行有3列,其他行有更多或更少的列。因此,当我使用.ThenBy扩展时,如果我试图在第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列第1列排序,然后我只需要按照第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对列表子集进行排序,但我可能需要解构最后的行集合,对其进行排序,然后重新构建集合。我本来希望避免这种情况。

3 个答案:

答案 0 :(得分:2)

您可以使用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的类型,可能有更好的方法来解决所有这些问题。

答案 1 :(得分:1)

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

答案 2 :(得分:0)

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

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;

我得到了这些结果:

Results