C# 如何根据项目';父母/子女关系?

C# 如何根据项目';父母/子女关系?,c#,list,C#,List,我的对象看起来像这样: public class Transaction { long Id; long Amount; DateTime Date; string ReferenceNumber; string ParentReferenceNumber; } 它已经按日期排序,但我需要做的是安排这些事务的列表,以便那些具有与另一个事务上的ReferenceNumber匹配的ParentReferenceNumber的事务以“父事务然后子事务”的顺序出现 这是我

我的对象看起来像这样:

public class Transaction
{
   long Id;
   long Amount;
   DateTime Date;
   string ReferenceNumber;
   string ParentReferenceNumber;
}
它已经按
日期
排序,但我需要做的是安排这些事务的列表,以便那些具有与另一个
事务
上的
ReferenceNumber
匹配的
ParentReferenceNumber
的事务以“父事务然后子事务”的顺序出现

这是我试过的。它会产生错误“集合已修改;枚举操作可能无法执行”。这正是我所担心的,因此产生了这个问题

foreach (var p in Model.PaymentInfo)
{
    var child = Model.PaymentInfo.SingleOrDefault(x => x.ParentReferenceNumber == p.ReferenceNumber);

    if (child != null)
    {
        var parentIndex = Model.PaymentInfo.IndexOf(p);
        var childIndex = Model.PaymentInfo.IndexOf(child);
        Model.PaymentInfo.RemoveAt(childIndex);
        Model.PaymentInfo.Insert(parentIndex + 1, child);
    }

}

您正在查找有关对象排序的信息。请查看此处以了解更多信息。


首先向每个节点添加子节点列表。例如:

public class WorkingTransaction
{
    public Transaction Details;
    public List<WorkingTransaction> Children;
    public bool HasParent;
}
现在,浏览字典,将那些具有父引用的项添加到父项的子项列表中,并更新
HasParent
标志。同时,任何没有父项的项都会添加到“根级别”列表中


您可以使用类似的递归方法以正确的顺序输出子项。

为了以简单的方式实现这一点,我必须创建一个新的列表。我不想更改客户端现有的对象结构。我是如何做到这一点的:

var sortedList = new List<Transaction>();

foreach (var p in ListOfTransactions)
{
    if (sortedList.Contains(p))
    {
        continue; // Don't add duplicates
    }

    sortedList.Add(p); //  Add the transaction

    var child = ListOfTransactions.SingleOrDefault(x => x.ParentReferenceNumber == p.ReferenceNumber);

    if (child != null) // Add the child, if exists
    {
        sortedList.Add(child);
    }
}
var sortedList=newlist();
foreach(交易清单中的var p)
{
if(分类列表包含(p))
{
继续;//不添加重复项
}
sortedList.Add(p);//添加事务
var child=ListOfTransactions.SingleOrDefault(x=>x.ParentReferenceNumber==p.ReferenceNumber);
if(child!=null)//添加子级(如果存在)
{
分类列表。添加(子项);
}
}

这不是简单的(顺序)排序。它需要匹配不同对象上的不同属性,以便按预期进行排序。很明显,您没有阅读本文,我刚才给您的示例完全符合您的要求,这将为您提供一个排序列表,其中包含匹配的属性值降序。您应该能够推断代码的其余部分。当您在集合中循环时,您永远无法从集合中删除该项。但是,再看一遍,您已经考虑过了,只需在select中添加一个groupby,然后在groupby上排序即可。这将在不需要大量额外代码的情况下满足您的需求。
var workDict = transactions
    .Select(t => new WorkingTransaction
        { 
            Details = t, 
            Children = new List<WorkingTransaction, 
            HasParent = false
         })
    .ToDictionary(t => t.Details.Id, t);
List<WorkingTransaction> rootParents = new List<WorkingTransaction>();

foreach (var kvp in workDict)
{
    WorkingTransaction parent;
    if (workDict.TryGetValue(kvp.Value.Details.ParentReferenceNumber, out parent)
    {
        parent.Children.Add(kvp.Value);
        kvp.Value.HasParent = true;
    }
    else
    {
        rootParents.Add(kvp.Value);
    }
}
foreach (var t in rootParents)
{
    processChildren(t.Children);
}

void ProcessChildren(WorkingTransaction t)
{
    t.Children = t.Children.OrderBy(child => child.Details.Id).ThenBy(child => child.Details.Date);
    // and recursively process the children of this transaction
    foreach (var child in t.Children)
    {
        ProcessChildren(child);
    }
}
var sortedList = new List<Transaction>();

foreach (var p in ListOfTransactions)
{
    if (sortedList.Contains(p))
    {
        continue; // Don't add duplicates
    }

    sortedList.Add(p); //  Add the transaction

    var child = ListOfTransactions.SingleOrDefault(x => x.ParentReferenceNumber == p.ReferenceNumber);

    if (child != null) // Add the child, if exists
    {
        sortedList.Add(child);
    }
}