5

What I want to achieve is a alphabetically sorted nested list.

E.g. my input:

fat, twat, gat    //Line 1
cat, hat, bat     // Line 2
twat, lack, rat   // Line 3

I want the output to be:

bat, cat, hat    // Line 2
fat, gat, twat   // Line 1
lack, rat, twat  // Line 3

As you can see, the list is sorted on the inside first, then also on the outside.

My implementation at the moment is using a nested list:

List<List<String>> testSort;

I have managed to sort the inside list using this method:

    public static List<List<String>> sortList(List<List<String>> input)
    {
        input.ForEach(delegate (List<string> o)
        {
            o.Sort();
        });

        return input;
    }

I'm unsure how to sort the list on the outside now. Help would be appreciated!

Thanks in advance!

4 Answers 4

9

You can use OrderBy() to sort the outside list based on first element of each list, after each internal list is already sorted:

input.ForEach(t => t.Sort());
input = input.OrderBy(t => t.First()).ToList();

In response to M.kazem Akhgary comment below, I can only think of this solution if you want the sorting of the outer list not only based on the first element but the entire list. Maybe someone else has better solution.

input.ForEach(t => t.Sort());
input.Sort((e1, e2) => {
    for (int i = 0; i < e1.Count; i++)
    {
        if(e1[i] != e2[i])
        {
            return e1[i].CompareTo(e2[i]);
        }
    }

    return 0;
});
Sign up to request clarification or add additional context in comments.

6 Comments

just wanted to know, what will be the effect, if I Sort() on input. i.e, input.Sort() ?
@Zeeshan : if you call sort directly on List<List> without any parameter, it will try to use default comparer to compare List<string> and List<string>. But there's none by default so there will be compilation error. In order to call Sort() on List<List>, you will need to tell the compiler how to compare 2 elements of type List<string>, by providing the Sort() with lambda expression or custom comparer
what about second element if first elements was equal?
@M.kazemAkhgary good point, I didn't really think about that. I modified my answer with another solution that I think of, feel free to suggest a better one if have
@M.kazemAkhgary good point. I have proposed an answer for that.
|
4

Since the signature of sortList has a return type it is best not to modify the contents of the input list - that could just lead to side effects and buggy code.

Here's how I would tackle this:

public static List<List<String>> sortList(List<List<String>> input)
{
    return input
        .Select(x => x.OrderBy(y => y).ToList())
        .OrderBy(x => String.Join(", ", x))
        .ToList();
}

So, given this input:

var input = new List<List<string>>()
{
    new List<string>() { "fat", "twat", "gat", },
    new List<string>() { "cat", "hat", "bat", },
    new List<string>() { "twat", "lack", "rat", },
};

This would be the output:

output

4 Comments

I think using string.Join() to produce key for comparison in OrderBy() might cause undesired effect. E.g. when comparing "twat" and "twa", it will compare the last "t" of the first element with "," character
@PhuongNguyen - It's better to have a dividing character than to not. What if the two strings were "ba", "ram" versus "bar", "am"? I thought it a fair choice to take the ", " separator from the OP's example, but it could equally well be "|".
You can sort with .OrderBy(x => String.Join(",", "["+x+"]")) to eliminate all influence from the containing elements like "bar, "
@M.kazemAkhgary - To which hack are you referring?
2

I'm unsure how to sort the list on the outside now.

Suppose you have sorted all the inner sub lists, now you can:

input = input.OrderBy(subList => String.Join(",", subList)).ToList();

This will join the sub lists to a single string for comparison, such that it will compare the second elements of the lists if the first elements are the same. And third if the second elements are the same...

There should be a separator in using String.Join(), to avoid accidentally used second elements when comparing first elements. The separator should not be appeared in the original string.

3 Comments

This doesn't order the inner list first.
@Enigmativity I will edit to clarify it, because the OP is only asking for sorting outer list.
The OP is asking to sort the outer list based on the values in the sorted inner list.
2

You can implement your own List comparer. without use of Linq

private static void Main()
{
    List<List<string>> list = new List<List<string>>
    {
        new List<string> {"fat", "twat", "gat"},
        new List<string> {"cat", "hat", "bat"},
        new List<string> {"twat", "lack", "rat"}
    };

    // sort the inner list
    foreach (var l in list)
    {
        l.Sort();
    }

    list.Sort(new ListComparer<string>()); // sort outer list according to ListComparer class.
}

This is the List Comparer.

class ListComparer<T> : Comparer<List<T>> where T : IComparable
{
    // Compare lists elements until they are no more equal.
    // return result of last compared elements as result.
    public override int Compare(List<T> x, List<T> y)
    {
        int compared = 0;
        for (int i = 0; compared == 0 && i < x.Count && i < y.Count ; i++)
        {
            compared = x[i].CompareTo(y[i]);
        }
        return compared;
    }
}

The method Compare returns an integer that indicates whether first list is bigger (1) or second one (-1). It will return 0 if both lists are equals.

The Sort method uses this results to sort out your list.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.