关于层次结构的 C# IComparer
C# IComparer with respect of the hierarchy
我实现了 IComparable / IComparer 用于自定义排序,但我需要保留一些层次结构。
我的 class :
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;
}
}
您的数据结构与 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。
这里是完整的代码,虽然不优雅但是可以工作。在比较器的构造函数中,我创建了一个跟踪 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; }
}
}
}
我实现了 IComparable / IComparer 用于自定义排序,但我需要保留一些层次结构。
我的 class :
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;
}
}
您的数据结构与 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。
这里是完整的代码,虽然不优雅但是可以工作。在比较器的构造函数中,我创建了一个跟踪 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; }
}
}
}