Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/sorting/2.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
C# 如何对这个分层列表进行排序? 问题_C#_Sorting_Hierarchical - Fatal编程技术网

C# 如何对这个分层列表进行排序? 问题

C# 如何对这个分层列表进行排序? 问题,c#,sorting,hierarchical,C#,Sorting,Hierarchical,我有一个无序的列表,其中每个项都可以通过一个唯一的ID指向列表中的另一个项 我想对列表进行排序,以便每个项后面都跟有它所指向的项 初始化列表 公共类项目{ 公共字符串ID{get;set;} 公共字符串nextID{get;set;} } void Main() { var items=新列表(); 添加(新项目{ID=“X”,nextID=”“}); 添加(新项目{ID=“A”,nextID=“D”}); 添加(新项目{ID=“C”,nextID=“B”}); 添加(新项目{ID=“E”,n

我有一个无序的
列表
,其中每个
都可以通过一个唯一的ID指向列表中的另一个

我想对列表进行排序,以便每个
后面都跟有它所指向的

初始化列表
公共类项目{
公共字符串ID{get;set;}
公共字符串nextID{get;set;}
}
void Main()
{
var items=新列表();
添加(新项目{ID=“X”,nextID=”“});
添加(新项目{ID=“A”,nextID=“D”});
添加(新项目{ID=“C”,nextID=“B”});
添加(新项目{ID=“E”,nextID=”“});
添加(新项目{ID=“B”,nextID=“A”});
添加(新项目{ID=“D”,nextID=”“});
SortItems(项目);
//应按以下顺序生成ID为的项目:[“X”、“E”、“C”、“B”、“A”、“D”]
}

通过使用拓扑排序函数
TSort()
,我编写了以下函数来按照我的规范进行排序:

public List<Item> sortItems(List<Item> items) {

    // perform a topological sort
    var sortedItems = 
        items.TSort(item => items.Where(o=>item.ID == o.nextID || item.nextID == ""))
        .ToList();

    // this next code moves the unpointed items to top of list

    // find items that are not pointed to, and do not point to any other item
    var soloItems= 
        sortedItems.Where(o => !sortedItems.Where(p => p.nextID == o.ID).Any() && o.nextID == "").ToList();

    // reverse the soloItems list so they
    // to appear in the same order in which 
    // they were found in unsorted list
    soloItems.Reverse();    

    // move the soloItems from the bottom of sortedItems to the top of sortedItems
    sortedItems.RemoveAll(o => soloItems.Contains(o));
    sortedItems.InsertRange(0,soloItems);

    return sortedItems;     

}
public List sortItems(列表项){
//执行拓扑排序
var-sortedItems=
items.TSort(item=>items.Where(o=>item.ID==o.nextID | | item.nextID==“”)
.ToList();
//下面的代码将未上色的项移动到列表的顶部
//查找未指向的项目,并且不要指向任何其他项目
var soloItems=
sortedItems.Where(o=>!sortedItems.Where(p=>p.nextID==o.ID).Any()&&o.nextID==“”)。ToList();
//反转soloItems列表,以便
//以相同的顺序出现
//在未分类的列表中找到了它们
soloItems.Reverse();
//将soloItems从sortedItems底部移动到sortedItems顶部
sortedItems.RemoveAll(o=>soloItems.Contains(o));
sortedItems.InsertRange(0,soloItems);
返回分拣机;
}

有趣的问题。起初,我想知道是否可以使用带有一些选择器委托的简单Linq查询构造,但这很快就会变得一团糟

下面简单的linq构造可以部分地帮助您,但实际上也需要使用和传播计数和原始输入顺序

// Simple Linq, but just not good enough
// Need to also propagate original input order and count the number of siblings
Func<IEnumerable<Item>, Item, IEnumerable<Item>> SelectSuccessors = (set, item) => set.Where(i => i.ID == item.nextID);
Func<IEnumerable<Item>, IEnumerable<Item>, IEnumerable<Item>> Flatten = null;
Flatten = (set, sibblingPool) => set
    .SelectMany(i => new[] { i }.Concat(Flatten(SelectSuccessors(sibblingPool.Except(set), i), sibblingPool.Except(set))));
var unparented = items.Where(i => !items.Any(n => n.nextID == i.ID));
foreach (var item in Flatten(unparented, items))
    Console.WriteLine(item.ID);

搜索词谢谢,我一定错过了算法课上的那一天。顺便说一句,如果你的项目没有指向任何东西,你应该有
nextID
be
null
,而不是空字符串。@Jandorenhaus:正确的一点,但在我的例子中,我的真实数据是以空字符串的形式从文本文件中输入的,我认为将<代码>“<代码> s转换为<代码> null <代码>是一个精度损失。我在上面手动创建
列表的代码
只是为了在SO上发布的好处。@WalterStabosz Fair:)
// Simple Linq, but just not good enough
// Need to also propagate original input order and count the number of siblings
Func<IEnumerable<Item>, Item, IEnumerable<Item>> SelectSuccessors = (set, item) => set.Where(i => i.ID == item.nextID);
Func<IEnumerable<Item>, IEnumerable<Item>, IEnumerable<Item>> Flatten = null;
Flatten = (set, sibblingPool) => set
    .SelectMany(i => new[] { i }.Concat(Flatten(SelectSuccessors(sibblingPool.Except(set), i), sibblingPool.Except(set))));
var unparented = items.Where(i => !items.Any(n => n.nextID == i.ID));
foreach (var item in Flatten(unparented, items))
    Console.WriteLine(item.ID);
public class ItemHierarchy : Tuple<Item, int, List<ItemHierarchy>>
{
    public static List<ItemHierarchy> BuildHierarchy(IEnumerable<Item> items)
    {
        var inputOrderNumbered = items.Select((item, order) => Tuple.Create(item, order));
        var roots = inputOrderNumbered.Where(i => !items.Any(n => n.nextID == i.Item1.ID));
        return roots.Select(r => BuildFor(r.Item1, r.Item2, inputOrderNumbered.Except(roots))).ToList();
    }

    public Item Item 
    { 
        get { return this.Item1; } 
    }
    public int OriginalInputOrder
    {
        get { return this.Item2; }
    }
    public int NumberOfDescendents
    {
        get { return this.Item3.Count + this.Item3.Sum(i => i.NumberOfDescendents); }
    }
    public IEnumerable<Item> Flattened
    {
        get { return new[] { this.Item }.Concat(Descendents); }
    }
    public List<ItemHierarchy> DescendentHierarchy
    {
        get { return this.Item3; }
    }
    public IEnumerable<Item> Descendents
    {
        get { return this.Item3.SelectMany(i => new [] { i.Item }.Concat(i.Descendents)); }
    }
    public IEnumerable<Item> Leafs
    {
        get
        {
            if (NumberOfDescendents == 0)
                return new[] { this.Item };
            else
                return DescendentHierarchy.SelectMany(d => d.Leafs);
        }
    }
    protected ItemHierarchy(Item item, int originalOrder, IEnumerable<Tuple<Item, int>> descendents, IEnumerable<Tuple<Item, int>> remaining)
        : base(item, originalOrder, descendents.Select(d => BuildFor(d.Item1, d.Item2, remaining)).ToList())
    {
    }

    private static ItemHierarchy BuildFor(Item item, int originalOrder, IEnumerable<Tuple<Item, int>> numberedSiblings)
    {
        var descendents = numberedSiblings.Where(s => s.Item1.ID == item.nextID);
        return new ItemHierarchy(item, originalOrder, descendents, numberedSiblings.Except(descendents));
    }
}
// This works quite well.
// As a bonus it preserves the original input information 
// and offers a navigatable/queryable hierarchy.
var hierarchy = ItemHierarchy.BuildHierarchy(items);
foreach (var item in hierarchy.OrderBy(r => r.NumberOfDescendents).ThenBy(r => r.OriginalInputOrder).SelectMany(r => r.Flattened))
    Console.WriteLine(item.ID);