简体   繁体   English

如何在 C# 中使用 LINQ 进行两级排序

[英]How can I do a two level sort with LINQ in C#

I have a List<string> object that looks like this:我有一个List<string> object 看起来像这样:

option 1
 line a
 line b
 line c
option 3
 line x
 line z
 line y
option 2
 a1
 a4
 a2
 a3

All the secondary details are indented one space.所有次要细节都缩进一个空格。 Is it possible to sort this list using LINQ?是否可以使用 LINQ 对该列表进行排序? I only know about the very basic ordering and don't really know where to start when it comes to trying to sort the secondary lines that have strings with a space in the first column.我只知道非常基本的排序,并且真的不知道在尝试对第一列中有空格的字符串的辅助行进行排序时从哪里开始。

Here's what I want the List to look like after sorting这是我希望列表排序后的样子

option 1
 line a
 line b
 line c
option 2
 a1
 a2
 a3
 a4
option 3
 line x
 line y
 line z

I just updated the question.我刚刚更新了这个问题。 I had List<string> but it got chopped when published.我有List<string>但它在发布时被砍掉了。

Use:利用:

yourEnumerable.OrderBy(y => y.Key).ThenBy(y => y.Prop2)

See the documentation at MSDN: http://msdn.microsoft.com/en-us/library/bb534966.aspx and http://msdn.microsoft.com/en-us/library/bb534743.aspx请参阅 MSDN 上的文档: http://msdn.microsoft.com/en-us/library/bb534966.aspxhttp://msdn.microsoft.com/en-us/library/bb534743.aspx

UPDATE: Try the code below to parse and sort, it's somewhat pseudo:更新:尝试下面的代码来解析和排序,它有点伪:

string lineRead;
string current;
var dictionary = new Dictionary<string, List<string>>);
while((lineRead = reader.ReadLine())
{
    if(!lineRead.StartsWith("  "))
    {
        dictionary.Add(lineRead, new List<string>());
        current = lineRead;
    }
    else
    {
        dictionary[current].Add(lineRead);
    }
}

dictionary.Keys.ToList().ForEach(y => dictionary[y] = dictionary[y].OrderBy(x => x).ToList());
dictionary.OrderBy(y => y.Key);

While there's no built-in way to do this, LINQ provides a simple, elegant answer:虽然没有内置方法可以做到这一点,但 LINQ 提供了一个简单、优雅的答案:

    static IEnumerable<string> Sort(IEnumerable<string> unsorted)
    {
        string option = null;
        return
            from line in unsorted
            let isSubitem = line.StartsWith(" ")
            let parent = isSubitem ? option : option = line
            orderby parent, isSubitem, line
            select line;
    }

The key is being able associate a sub-item (a line starting with a space) with its parent option (a line with no space at the beginning).关键是能够将子项(以空格开头的行)与其父选项(开头没有空格的行)相关联。 We do this by first declaring a local variable option which will always hold the current parent option.为此,我们首先声明一个局部变量option ,该选项将始终保存当前父选项。

Within the LINQ expression, the first thing to do is tell it to iterate over the items in the unsorted input, giving each string the name line .在 LINQ 表达式中,首先要做的是告诉它遍历unsorted输入中的项目,为每个字符串赋予名称line Then we determine whether it's a sub-item, and put that result in isSubItem .然后我们确定它是否是一个子项,并将结果放入isSubItem

Now comes the key -- putting the parent option into parent .现在是关键 - 将 parent 选项放入parent If the line is a sub-item, it just uses the stored option .如果该行是一个子项,它只使用存储的option If it's not, the option = line part stores the current line as option and assigns it to parent .如果不是,则option = line部分将当前行存储为option并将其分配给parent

Then it's just a simple matter of sorting, first by the parent option, then by whether a line is a parent (to make sure that the parent always shows up before its children), and then by the sub-items.那么这只是一个简单的排序问题,首先是父选项,然后是一行是否是父项(以确保父项总是出现在其子项之前),然后是子项。

If you want to use the shorter lambda-based syntax and don't want the readibility of extra names, you can do it quite simply in just a coule lines:如果您想使用较短的基于 lambda 的语法并且不希望额外名称的可读性,您可以非常简单地在几行代码中完成:

    static IEnumerable<string> Sort(IEnumerable<string> unsorted)
    {
        string option = null;
        return
            unsorted
            .OrderBy(line => line.StartsWith(" ") ? option : option = line)
            .ThenBy(line => line.StartsWith(" ") ? line : null);
    }
list.OrderBy(<a delegate that will sort your array>).ThenBy(<a delegate that will sort your array again>)

is that what you wnat?那是你想要的吗?

well I answered it based on your question and this is how the delegate will be, your first delegate will basically group the items under each of the options and then sort it and the next delegate will sort each of the items that fall under the option tag..好吧,我根据您的问题回答了它,这就是代表的方式,您的第一个代表基本上会将每个选项下的项目分组,然后对其进行排序,下一个代表将对选项标签下的每个项目进行排序..

An alternate approach would be to store this in a dictionary: as follows: Key Value(List) option1 a1, a2 etc option2 as1,as2 etc etc.另一种方法是将其存储在字典中:如下所示:Key Value(List) option1 a1, a2 etc option2 as1,as2 etc etc.

then you will sort the value and the key and then if you want put it into a list if needed only然后您将对值和键进行排序,然后如果您只想在需要时将其放入列表中

Something like:就像是:

                    .OrderBy(x => x.option)
                    .ThenBy(x=>x.secondary)

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM