开发者

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

I have a List<string> object that looks like this:

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? 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 t开发者_开发百科he 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.


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

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:

    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.

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. Then we determine whether it's a sub-item, and put that result in isSubItem.

Now comes the key -- putting the parent option into parent. If the line is a sub-item, it just uses the stored option. If it's not, the option = line part stores the current line as option and assigns it to 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:

    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);
    }


Something like:

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


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.

then you will sort the value and the key and then if you want put it into a list if needed only

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜