在Linq中进行父子排序

8

意图是按照父级和子级(只有一个子级)的顺序对列表进行排序。

Example Set:
ID  ParentId Type   Unit
1   NULL    Energy  kJ
2   1       Cal
3   NULL    Protein g
4   NULL    Fat, total  g
5   4       Saturated   g
6   NULL    Carbohydrate    g
7   6       Sugars  g
8   NULL    Dietary fibre   g
10  NULL    Sodium  mg
11  NULL    Potassium   mg

例如,如果我按类型排序(按字母顺序),它将显示

  1. 碳水化合物
  2. 糖类(父级= 1.)
  3. 膳食纤维
  4. 能量
  5. 卡路里(父级= 4.)
  6. 总脂肪
  7. 饱和脂肪(父级= 6.)

1
当你说“按父级再按子级”,你是指ID吗?还是你想看到P1,C1,P2,C2,P3,C3等等...?这是一个好问题,只是不太清楚你想要看到什么结果。也许可以提供一个样例来展示你期望的结果? - James Michael Hare
@JamesMichaelHare 增加了预期集合。 - ediblecode
我会假设从你的数据中可以保证子ID永远不会大于父ID,是这样吗? - James Michael Hare
@iMortalitySX 我不认为这是那么简单的。OP 实际上想要将列表加入到它自己上面。 - James Michael Hare
1
LINQ中的多重排序 - iMortalitySX
显示剩余3条评论
3个回答

6

试试这个:

return myData.Select(x => new { key = (x.Parent ?? x).Type, item = x})
             .OrderBy(x => x.key)
             .ThenBy(x => x.item.Parent != null)
             .Select(x => x.item);

这个可以用。给未来的用户:应该是 .ThenBy(x => x.item.Parent == null) - ediblecode
糟糕,已经修改了。感谢你的发现。 - Bobson
1
啊,是的,这实际上并不起作用,只是因为我的数据已经按正确的顺序排列了,所以看起来好像可以。 - ediblecode
嗯。尝试在.ThenBy()之后加上.ToList()?强制它在修改我们选择的内容之前评估排序。 - Bobson
@danrhul - 我刚刚有机会实际尝试了一下。我只需要反转ThenBy()。请尝试当前版本。 - Bobson
显示剩余2条评论

1

这可以分为两个步骤完成。首先 - 建立父子层次结构(并对其进行排序):

var query = from parent in data
            where parent.ParentId == null
            orderby parent.Type
            join child in data on parent.ID equals child.ParentId into g
            select new { Parent = parent, Children = g };

第二 - 奉承的等级制度

var result = query.Flatten(x => x.Parent, x => x.Children);

为了使代码更简洁,我使用了扩展方法:

public static IEnumerable<TResult> Flatten<T, TResult>(
    this IEnumerable<T> sequence, 
    Func<T, TResult> parentSelector,
    Func<T, IEnumerable<TResult>> childrenSelector)
{
    foreach (var element in sequence)
    {
        yield return parentSelector(element);

        foreach (var child in childrenSelector(element))
            yield return child;
    }
}    

0

这应该可以工作

var query = from p in context.Table
            from c in context.Table.Where(x => p.ID == x.ParentId)
                                   .DefaultIfEmpty()
            let hasNoParent = c == null
            orderby hasNoParent ? p.Type : c.Type, hasNoParent ? 0 : 1
            select hasNoParent ? p.Type : c.Type;

当前上下文中似乎不存在 c - ediblecode
@danrhul - 抱歉,应该是 x.ParentId。 - Aducci
很抱歉,它没有起作用,有6个空值,后面是随机重复的数据。 - ediblecode
我之前没有注意到 p : c 的变化。即便如此,它只是复制了几个记录,然后按字母顺序显示它们。 - ediblecode

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接