OrderBy嵌套集合

时间:2015-12-29 10:49:18

标签: c# sorting

我正在尝试对这个复杂的对象进行排序:

Order _sut = new Order
{
    OrderDataArray = new[]
    {
        new OrderData
        {
            OrderHeaderArray = new[]
            {
                new OrderHeader
                {
                    SequenceNumber = 1,
                    OrderPositionArray = new[]
                    {
                        new OrderPositions
                        {
                            LineNumber = 3
                        },
                        new OrderPositions
                        {
                            LineNumber = 2
                        },
                        new OrderPositions
                        {
                            LineNumber = 1
                        }
                    }
                }
            }
        }
    }
};

使用代码:

[Fact]
public void Sorts_By_Sequence_Number()
{
    var ordered = _sut.OrderDataArray
        .OrderBy(o => o.OrderHeaderArray
            .OrderBy(a => a.OrderPositionArray
                .OrderBy(p => p.LineNumber)))
        .ToArray();

    _sut.OrderDataArray = ordered;
    OutputHelper(_sut);
}

我不明白为什么这不起作用,这意味着排序例程只保留LineNumber对象的初始顺序。我用OrderBy尝试了各种各样的东西,但看起来它没有排序。

修改

感谢您的回复,两者都是正确的。我已经接受了poke的响应,因为它提供了有关OrderBy方法内部工作的更详细信息。基本上我在循环中错过了赋值,我试图一次对所有对象进行排序。

2 个答案:

答案 0 :(得分:2)

您应该考虑OrderBy的作用。它按照您在lambda表达式中确定的值对集合进行排序,然后返回一个可枚举的。

你的外线电话有利于此:

_sut.OrderDataArray.OrderBy(o => something).ToArray();

您按某种方式排序,然后将结果转换为(然后排序的)数组。这里有两件事情重要:首先,至少在你的例子中,OrderDataArray中只有一个对象,所以没有发生任何排序。其次,它取决于something这些对象如何排序的返回值。

那么在那种情况下,something是什么?它是以下内容:

o.OrderHeaderArray.OrderBy(a => somethingElse)

所以无论somethingElse如何,这又回归了什么?一个IEnumerable<OrderHeader>。多个枚举如何相互比较?它们不具有可比性;并且他们特别不会根据他们的内容告诉您有关订单的任何信息(您必须首先枚举它)。基本上,你通过“别的东西”订购OrderHeaderArray,使用不会告诉你任何订单的结果作为订购OrderDataArray的关键。然后,您将已排序的OrderHeaderArray扔掉。

你使用OrderPositionArray更深入地执行一个级别,这也不会做任何有用的事情。唯一真正有用的排序发生在OrderPositionArray本身,但结果再次丢弃。

现在,如果你想订购你的结构,你应该通过将排序的结构重新分配到数组来正确地进行。因此,在某些时候,您必须执行以下操作:

a.OrderPositionArray = a.OrderPositionArray.OrderBy(p => p.LineNumber).ToArray();

但是除了OrderPositionArray本身和OrderHeader之外,你真的没有任何可以排序的东西(因为你不能按照子集合的顺序对集合进行真正的排序)。所以你可以这样解决它:

foreach (OrderData data in _sut.OrderDataArray)
{
    foreach (OrderHeader header in data.OrderHeaderArray)
    {
        header.OrderPositionArray = header.OrderPositionArray.OrderBy(p => p.LineNumber).ToArray();
    }

    data.OrderHeaderArray = data.OrderHeaderArray.OrderBy(h => h.SequenceNumber).ToArray();
}

除了Linq之外,您还可以对数组进行就地排序,这可能会因为您没有创建新的内部数组而使它更好一些:

var c = Comparer<int>.Default;
foreach (OrderData data in _sut.OrderDataArray)
{
    foreach (OrderHeader header in data.OrderHeaderArray)
    {
        Array.Sort(header.OrderPositionArray, new Comparison<OrderPositions>((x, y) => c.Compare(x.LineNumber, y.LineNumber)));
    }

    Array.Sort(data.OrderHeaderArray, new Comparison<OrderHeader>((x, y) => c.Compare(x.SequenceNumber, y.SequenceNumber)));
}

答案 1 :(得分:0)

在这里,

var ordered = _sut.OrderDataArray.OrderBy(o => ...

期望Func<OrderData, TKey>,并且将通过比较此函数执行的结果对值进行排序。

同时,您传递另一个OrderBy的结果,即IOrderedEnumerable。它根本没有多大意义。

为了对所有嵌套集合进行排序,您可以执行以下操作:

foreach (var orderData in _sut.OrderDataArray)
{
  foreach (var orderHeader in orderData.OrderHeaderArray)
  {
    orderHeader.OrderPositionArray = orderHeader.OrderPositionArray
        .OrderBy(x => x.LineNumber).ToArray();
  }

  orderData.OrderHeaderArray = orderData.OrderHeaderArray
      .OrderBy(x => x.SequenceNumber).ToArray();
}

_sut.OrderDataArray = _sut.OrderDataArray
    .OrderBy(x => ...).ToArray();

按照项目“OrderPositionArray对每个LineNumber项目进行排序。” 它按标题'OrderHeaderArray对每个SequenceNumber进行排序。

但是,目前还不清楚如何对_sut.OrderDataArray进行排序 - 在示例中标记为x => ...
它没有可用于分类的可比性质。