有关层次结构的C#IComparer

时间:2018-08-10 16:47:28

标签: c# hierarchical-data icomparable icomparer

我实现了IComparable / IComparer进行自定义排序,但是我需要保留一些层次结构。

我的课:

public class Attribut : IComparable
{
    public int       ATT_ID          { get; set; }
    public string    ATT_LIBELLE     { get; set; }
    public int       ATT_PARENT_ID   { get; set; }
}

测试数据如下:

ATT_ID      ATT_LIBELLE                         ATT_PARENT_ID   
356         Avis client requis                  0
357         Nom du destinataire client          356
358         Date d'envoi au client pour avis    356
366         CNPE ?                              0
367         Palier                              366
368         Tranche                             366
369         Site                                366 
370         Materiel                            366
371         Machine                             366
372         Affaire parent                      366

我想对ATT_LIBELLE进行升序/降序,但要尊重层次结构。

仅供参考,在Oracle下有子句Order By Siblings。 C#中没有等效项吗?

这是升序的理想结果:

ATT_ID      ATT_LIBELLE                         ATT_PARENT_ID   
356         Avis client requis                  0
358         Date d'envoi au client pour avis    356
357         Nom du destinataire client          356
366         CNPE ?                              0
372         Affaire parent                      366
371         Machine                             366
370         Materiel                            366
367         Palier                              366
369         Site                                366
368         Tranche                             366

这是下降所需的结果:

ATT_ID      ATT_LIBELLE                         ATT_PARENT_ID   
366         CNPE ?                              0
368         Tranche                             366
369         Site                                366
367         Palier                              366
370         Materiel                            366
371         Machine                             366
372         Affaire parent                      366
356         Avis client requis                  0
357         Nom du destinataire client          356
358         Date d'envoi au client pour avis    356

在C#中有可能吗?

谢谢!

编辑:

这是IComparable实现的代码:

public static IComparer sortAscending_ATT_LIBELLE       { get { return new sortLibelleAscendingHelper(); } }
public static IComparer sortDescending_ATT_LIBELLE      { get { return new sortLibelleDescendingHelper(); } }

private class sortLibelleAscendingHelper : IComparer
{
    int IComparer.Compare(object a, object b)
    {
        var oAtta = (a as Attribut);
        var oAttb = (b as Attribut);

        if (a == null || b == null) { return 0; }

        int ret = (oAtta.ATT_LIBELLE).CompareTo(oAttb.ATT_LIBELLE);

        if ((oAtta.ATT_PARENT_ID != oAttb.ATT_PARENT_ID) || (oAtta.ATT_PARENT_ID == oAttb.ATT_ID))
        {
            ret = 1;
        }

        return ret;
    }
}

private class sortLibelleDescendingHelper : IComparer
{
    int IComparer.Compare(object a, object b)
    {
        var oAtta = (a as Attribut);
        var oAttb = (b as Attribut);

        if (a == null || b == null) { return 0; }

        int ret = (oAttb.ATT_LIBELLE).CompareTo(oAtta.ATT_LIBELLE);

        if ((oAtta.ATT_PARENT_ID != oAttb.ATT_PARENT_ID) || (oAtta.ATT_PARENT_ID == oAttb.ATT_ID))
        {
            ret = -1;
        }

        return ret;
    }
}

2 个答案:

答案 0 :(得分:1)

您的数据结构与IComparable不兼容。 IComparable实现成对比较:换句话说,给定任意两个元素,您需要能够知道它们的相对顺序。在您的示例中,这是不可能的,因为您的数据结构是一棵树,并且比较两个元素需要整个树结构的上下文。

实现对数据进行排序的挑战在于,您正在使用的表示形式是扁平化的关系表示形式。可能有一种聪明的就地排序方式,但是如果将其转换为这样的内存树表示形式,则排序变得很简单:

public class AttributNode
{
    public Attribut       ATTRIBUT        { get; set; }
    public AttributNode[] CHILDREN        { get; set; }

    public void Sort() {
        foreach (Attribut child in CHILDREN) {
            child.Sort();
        }

        Array.Sort(
            CHILDREN,
            (x, y) => x.ATTRIBUT.ATT_LIBELLE.CompareTo(y.ATTRIBUT.ATT_LIBELLE));
    }

    IEnumerator<Attribut> Flatten()
    {
        yield return ATTRIBUT;

        foreach (IEnumerable<Attribut> items in CHILDREN.Select((c) => c.Flatten()))
        {
            foreach (Attribut item in items) {
                yield return item;
            }
        }
    }
}

从扁平化的表示形式构建树中应该涵盖其他答案like this one

答案 1 :(得分:1)

这里是完整的代码,它不是很优雅,但是可以正常工作。在比较器的构造函数中,我创建了一个影子字典,记录了Parent_Libelle。这是为了进行正确的排序。 您可以通过将Order设置为true来进行升序排序。

using System;
using System.Collections.Generic;
using System.Reflection;
using System.Linq;

namespace ConsoleApp1
{
    class Program
    {

        static void Main(string[] args)
        {
            List<Attribut> sortList = new List<Attribut>();
            sortList.Add(new Attribut() { ATT_ID = 356, ATT_LIBELLE = "Avis client requis", ATT_PARENT_ID = 0 });
            sortList.Add(new Attribut() { ATT_ID = 357, ATT_LIBELLE = "Nom du destinataire client", ATT_PARENT_ID = 356 });
            sortList.Add(new Attribut() { ATT_ID = 358, ATT_LIBELLE = "Date d'envoi au client pour avis", ATT_PARENT_ID = 356 });
            sortList.Add(new Attribut() { ATT_ID = 366, ATT_LIBELLE = "CNPE ?", ATT_PARENT_ID = 0 });
            sortList.Add(new Attribut() { ATT_ID = 367, ATT_LIBELLE = "Palier", ATT_PARENT_ID = 366 });
            sortList.Add(new Attribut() { ATT_ID = 368, ATT_LIBELLE = "Tranche", ATT_PARENT_ID = 366 });
            sortList.Add(new Attribut() { ATT_ID = 369, ATT_LIBELLE = "Site", ATT_PARENT_ID = 367 });
            sortList.Add(new Attribut() { ATT_ID = 370, ATT_LIBELLE = "Materiel", ATT_PARENT_ID = 367 });
            sortList.Add(new Attribut() { ATT_ID = 371, ATT_LIBELLE = "Machine", ATT_PARENT_ID = 366 });
            sortList.Add(new Attribut() { ATT_ID = 372, ATT_LIBELLE = "Affaire parent", ATT_PARENT_ID = 366 });



            Random rand = new Random();
            for (int i = 0; i < 30; i++)
            {
                int ra = rand.Next(10);
                Attribut move = sortList[ra];
                sortList.RemoveAt(ra);
                sortList.Add(move);
            }

            sortList.Sort(new CompareAttribut(sortList, false));

            foreach (Attribut oneAtt in sortList)
            {
                Console.WriteLine(oneAtt.ATT_ID + " " + oneAtt.ATT_LIBELLE + " " + oneAtt.ATT_PARENT_ID);
            }

        }

        public class CompareAttribut : IComparer<Attribut>
        {
            private class AttributTree
            {
                private Attribut self;
                public AttributTree(Attribut Self)
                {
                    self = Self;
                }
                public Attribut Self
                {
                    get { return self; }
                }
                public AttributTree Parent { get; set; }

                public string [] SortorderLib { get; set; }

            }

            private bool order = false;

            private Dictionary<int,AttributTree> kHelpers = new Dictionary<int, AttributTree>();
            public CompareAttribut(List<Attribut> StartList, bool Order)
            {

                order = Order;

                foreach (Attribut a in StartList)
                {
                    int key = a.ATT_ID;
                    AttributTree at = new AttributTree(a);


                    //string value = a.ATT_PARENT_ID > 0 ? StartList.Single(p => p.ATT_ID == a.ATT_PARENT_ID).ATT_LIBELLE : a.ATT_LIBELLE;

                    kHelpers.Add(key, at);
                }

                //Create the tree
                foreach (AttributTree at in kHelpers.Values)
                {
                    at.Parent = kHelpers[at.Self.ATT_ID];
                }

                foreach (AttributTree at in kHelpers.Values)
                {
                    List<string> libelles = new List<string>();
                    libelles.Add(at.Self.ATT_LIBELLE);
                    AttributTree up = at;

                    while (up.Self.ATT_PARENT_ID != 0)
                    {
                        up = kHelpers[up.Self.ATT_PARENT_ID];
                        libelles.Insert(0, up.Self.ATT_LIBELLE);
                    }

                    at.SortorderLib = libelles.ToArray();
                }



            }

            public int Compare(Attribut x, Attribut y)
            {
                string[] xParentLib = kHelpers[x.ATT_ID].SortorderLib;
                string[] yParentLib = kHelpers[y.ATT_ID].SortorderLib;

                int i = 0;

                int outcome = 0;
                while (outcome == 0)
                {
                    if (i == xParentLib.Length) outcome = -1;//x above y
                    else if (i == yParentLib.Length) outcome = 1;//x  under y
                    else outcome = xParentLib[i].CompareTo(yParentLib[i]);
                    if (outcome == 0)
                    {
                        i++;
                        continue;
                    }
                    break;
                }
                return outcome * (order ? 1 : -1); 
            }
        }

        public class Attribut
        {
            public int ATT_ID { get; set; }
            public string ATT_LIBELLE { get; set; }
            public int ATT_PARENT_ID { get; set; }
        }
    }
}