简体   繁体   中英

Linq query to orderby level then parent and child item

I have looked up some orderby examples but I'm still confused about the best linq expression to sort the assembly in the code to produce this list:

Level Parent      Child  
1     L010057501U 231-100-002  
1     L010057501U 307-355-022  
2     307-355-022 307-355-058  
3     307-355-058 355-100-008  
3     307-355-058 357-200-002  
2     307-355-022 307-355-059  
3     307-355-059 355-200-005  
3     307-355-059 357-100-002  

The results needs to be sorted by level but the child needs to be immediately after the parent before the next parent is listed. The components of the assembly could be several levels deep. I hope I have explained adequately.

    class Program
{
    static void Main(string[] args)
    {
        SortAssembly();
        Console.ReadLine();
    }
    class Assembly
    {
        public int Level { get; set; }
        public string Parent { get; set; }
        public string Component { get; set; }
    }

    private static void SortAssembly()
    {
        Assembly[] assemblies = { 
            new Assembly { Level=1, Parent="L010057501U", Component="231-100-002" },
            new Assembly { Level=1, Parent="L010057501U", Component="307-355-022" },
            new Assembly { Level=2, Parent="307-355-022", Component="307-355-058" },
            new Assembly { Level=2, Parent="307-355-022", Component="307-355-059" },
            new Assembly { Level=3, Parent="307-355-058", Component="355-100-008" },
            new Assembly { Level=3, Parent="307-355-059", Component="355-200-005" },
            new Assembly { Level=3, Parent="307-355-059", Component="357-100-002" },
            new Assembly { Level=3, Parent="307-355-058", Component="357-200-002" }
        };

        var query = ???  

        foreach (var part in query)
        {
            Console.WriteLine("{0} - {1} - {2}", part.Level, part.Parent, part.Component);
        }
    }
}

1 - L010057501U - 231-100-002
1 - L010057501U - 307-355-022
____2 - 307-355-022 - 307-355-058
________3 - 307-355-058 - 355-100-008
________3 - 307-355-058 - 357-200-002
____2 - 307-355-022 - 307-355-059
________3 - 307-355-059 - 355-200-005
________3 - 307-355-059 - 357-100-002

I tried to implement the IComparable but I'm not grasping it. Still need help on this.

you can try the following

using System;
using System.Linq;


    public class Assembly
    {
        public int Level { get; set; }
        public string Parent { get; set; }
        public string Component { get; set; }
        public bool Visited{get;set;} // to track visited levels
    }
public class Program
{
    public static void Main()
    {
                Assembly[] assemblies = { 
            new Assembly { Level=1, Parent="L010057501U", Component="231-100-002" },
            new Assembly { Level=1, Parent="L010057501U", Component="307-355-022" },
            new Assembly { Level=2, Parent="307-355-022", Component="307-355-058" },
            new Assembly { Level=2, Parent="307-355-022", Component="307-355-059" },
            new Assembly { Level=3, Parent="307-355-058", Component="355-100-008" },
            new Assembly { Level=3, Parent="307-355-059", Component="355-200-005" },
            new Assembly { Level=3, Parent="307-355-059", Component="357-100-002" },
            new Assembly { Level=3, Parent="307-355-058", Component="357-200-002" }
        };
        DisplayAssemblies(assemblies);

    }

    private static void DisplayAssemblies(Assembly[] data)
    {
        // order the data to be sorted by levels
        var levels=data.OrderBy(t=>t.Level);
        foreach(var level in levels)
            if(!level.Visited)
                DisplayLevel(level,data);

    }

    private static void DisplayLevel(Assembly level, Assembly[] data)
    {
        var childs=data.Where(t=>t.Parent==level.Component).ToArray();
        Console.WriteLine("{0} - {1} - {2}", level.Level, level.Parent, level.Component);
        level.Visited=true;
        foreach(var child in childs)
        {       
            DisplayLevel(child,data);
        }
    }
}

OUTPUT:


1 - L010057501U - 231-100-002
1 - L010057501U - 307-355-022
2 - 307-355-022 - 307-355-058
3 - 307-355-058 - 355-100-008
3 - 307-355-058 - 357-200-002
2 - 307-355-022 - 307-355-059
3 - 307-355-059 - 355-200-005
3 - 307-355-059 - 357-100-002

here a Live DEMO

hope this will help you

Have your Assembly class implement IComparable which allows you to define how they are ordered by implementing its only method: CompareTo()

I THINK you were saying that you need to order first by Level, then Parent, then Component. If so you could use something like this:

class Assembly:IComparable
{
    public int Level { get; set; }
    public string Parent { get; set; }
    public string Component { get; set; }

    public int CompareTo(object obj)
    {
        var other = obj as Assembly;

        if (this.Level != other.Level)
        {
            return this.Level.CompareTo(other.Level);
        }

        if (this.Parent != other.Parent)
        {
            return this.Parent.CompareTo(other.Parent);
        }

        return this.Component.CompareTo(other.Component);
    }
}

But, if I have misunderstood your logic, then the idea is to have CompareTo() return a positive integer if this comes before other and a negative integer if other comes before this (or 0 if they are of equal rank).

Once you have IComparable implemented you can just do:

query = assemblies.OrderBy(a => a);

in order to sort the Assemly objects by your own custom ordering

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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