简体   繁体   English

排序列表<list<string> &gt; </list<string>

[英]Sorting List<List<string>>

I have a List of List which can be of variable but repeated width.我有一个列表列表,它可以是可变但重复的宽度。 For example:例如:

var test = new List<List<string>>();
test.Add(new List<string> {"1","2","3"});
test.Add(new List<string> {"1","4","12"});
test.Add(new List<string> {"1","2","9"});
test.Add(new List<string> {"1","4","5"});
test.Add(new List<string> {"6","7","8"});

But it could also be:但也可能是:

var test = new List<List<string>>();
test.Add(new List<string> {"1","2","3","3","3"});
test.Add(new List<string> {"1","4","12","1","7"});
test.Add(new List<string> {"1","2","9","9","4"});
test.Add(new List<string> {"1","4","5","8","5"});
test.Add(new List<string> {"6","7","8","2","7"});

It will never be:它永远不会是:

var test = new List<List<string>>();
test.Add(new List<string> {"1"});
test.Add(new List<string> {"1","5"});
test.Add(new List<string> {"1","2","3"});
test.Add(new List<string> {"1","5"});
test.Add(new List<string> {"6","7","8"});

And I would like to have the list ordered left column to right column like:我想让列表从左列到右列排序,例如:

["1","2","3"];
["1","2","9"];
["1","4","5"];
["1","4","12"];
["6","7","8"];

The following is a little test I setup to see what I could come up with ( https://dotnetfiddle.net/B5ljig ):以下是我设置的一个小测试,看看我能想出什么( https://dotnetfiddle.net/B5ljig ):

var test = new List<List<string>>();
test.Add(new List<string> {"1","2","3"});
test.Add(new List<string> {"1","4","5"});
test.Add(new List<string> {"1","2","3"});
test.Add(new List<string> {"1","4","5"});
test.Add(new List<string> {"6","7","8"});

var query = test.AsQueryable();
query = query.OrderBy(a=>a[0]);
var max = categories.Select(a=>a.Count()).Max();
for (int i = 1; i < max; i++)
{
    query = query.ThenBy(a=>a[i]); // Error Here
}
var sorted = query.ToList();

Unfortunately the commented line errors with不幸的是,注释行错误

'IQueryable>' does not contain a definition for 'ThenBy' and no accessible extension method 'ThenBy' accepting a first argument of type 'IQueryable>' could be found (are you missing a using directive or an assembly reference?) “IQueryable>”不包含“ThenBy”的定义,并且找不到接受“IQueryable>”类型的第一个参数的可访问扩展方法“ThenBy”(您是否缺少 using 指令或程序集引用?)

Any ideas?有任何想法吗? Thoughts?想法? Better ways.更好的方法。

If you want to Sort anything using your own rules , you can implement a custom comparer ( IComparer<T> ), IComparer<IList<string>> in this particular case:如果您想使用自己的规则对任何内容进行Sort ,则可以在这种特殊情况下实现自定义比较器IComparer<T>IComparer<IList<string>>

   public class MyListComparer : IComparer<IList<string>> {
      private static int CompareItems(string left, string right) {
        if (left.StartsWith("-"))
          if (right.StartsWith("-"))
            return -CompareItems(left.TrimStart('-'), right.TrimStart('-'));
          else
            return -1;
        else if (right.StartsWith("-"))
          return 1;

        left = left.TrimStart('0');
        right = right.TrimStart('0');  

        int result = left.Length.CompareTo(right.Length);

        if (result != 0)
          return result;

        for (int i = 0; i < left.Length; ++i) {
          result = left[i] - right[i];

          if (result != 0)
            return result;
        }

        return 0;
      }

      public int Compare(IList<string> x, IList<string> y) {
        if (ReferenceEquals(x, y))
          return 0;
        else if (null == x)
          return -1;
        else if (null == y)
          return 1;

        for (int i = 0; i < Math.Min(x.Count, y.Count); ++i) {
          int result = CompareItems(x[i], y[i]);

          if (result != 0)
            return result;
        }

        return x.Count.CompareTo(y.Count);
      }
    }

Then sort:然后排序:

  var test = new List<List<string>>();

  test.Add(new List<string> { "1", "2", "3" });
  test.Add(new List<string> { "1", "4", "12" });
  test.Add(new List<string> { "1", "2", "9" });
  test.Add(new List<string> { "1", "4", "5" });
  test.Add(new List<string> { "6", "7", "8" });

  // Time to sort with a custom comparer
  test.Sort(new MyListComparer());

  string report = string.Join(Environment.NewLine, test
    .Select(line => string.Join(", ", line)));

  Console.Write(report);

Outcome:结果:

  1, 2, 3
  1, 2, 9
  1, 4, 5
  1, 4, 12
  6, 7, 8

you can use the comparer with Linq query as well:您也可以将比较器与Linq查询一起使用:

  var sorted = test.OrderBy(new MyListComparer());

The problem is问题是

1) the overuse of IQueryable , you don't need it, 1)过度使用IQueryable ,你不需要它,

2) the fact that i is actually captured , and when the query is executed, you have all "then by" that use the same i == 3, the last value after the end of the for loop, (Hence, an out of bounds exception at runtime) 2) i实际上被捕获的事实,并且在执行查询时,您拥有所有使用相同 i == 3 的“then by”,即for循环结束后的最后一个值,(因此,运行时边界异常)

Here is a working version ( dotnetFiddle ):这是一个工作版本( dotnetFiddle ):

    var query = test.OrderBy(a=>a[0]);
    //var max = test.Select(a=>a.Count()).Max(); // If you say all lists have the same length, use `First(a => a.Count())` instead! And if they don't, then this will lead to an exception.

    for (int i = 1; i < max; i++)
    {
        var j = i; // Intermediary variable so that 'global' i is not captured.
        query = query.ThenBy(a=>a[j]);
    };
    var sorted = query.ToList();

On additional note, there are other solutions that use different approaches, already given, I think they feel more "idiomatic" for C# with the IComparer另外需要注意的是,还有其他使用不同方法的解决方案,已经给出,我认为他们对使用IComparer的 C# 感觉更“惯用”

There are two issues with your code.您的代码有两个问题。 One is a syntax issue and one is a logic issue.一个是语法问题,一个是逻辑问题。 To remove the compilation error you are seeing, the query variable must be an IOrderedQueryable instead of the IQueryable that you have listed.要删除您看到的编译错误,查询变量必须是 IOrderedQueryable 而不是您列出的 IQueryable。 If you combine the query variable definition and initial ordering in to one line like below, your issue should resolve.如果您将查询变量定义和初始排序组合成一行,如下所示,您的问题应该可以解决。

var query = test.AsQueryable().OrderBy(a => a[0]);

You could also use the IOrderedEnumerable instead using您也可以使用 IOrderedEnumerable 而不是使用

var query = test.OrderBy(a => a[0]);

The logic issue is that your code will not produce the result you are expecting.逻辑问题是您的代码不会产生您期望的结果。 You are ordering the list of the list of strings by its first value before ordering each list of strings.在对每个字符串列表进行排序之前,您正在按其第一个值对字符串列表列表进行排序。 In other words, your initial Orderby needs to be below your for loop.换句话说,您的初始 Orderby 需要低于您的 for 循环。 For simplicity I'm simplifying to this Linq expression:为简单起见,我将简化为此 Linq 表达式:

var sorted = test
    .Select(x => x.OrderBy(y => y).ToList())
    .OrderBy(x => x[0])
    .ToList();

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

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