How to sort depended objects by dependency

后端 未结 10 546
青春惊慌失措
青春惊慌失措 2020-11-28 19:31

I have a collection:

List> dependencyHierarchy;

The first item in pair is some object (item) and the

10条回答
  •  Happy的楠姐
    2020-11-28 20:03

    I merged DMM's idea with the depth-first-search algorithm on Wikipedia. It works perfect for what I needed.

    public static class TopologicalSorter
    {
    public static List LastCyclicOrder = new List(); //used to see what caused the cycle
    
    sealed class ItemTag
    {
      public enum SortTag
      {
        NotMarked,
        TempMarked,
        Marked
      }
    
      public string Item { get; set; }
      public SortTag Tag { get; set; }
    
      public ItemTag(string item)
      {
        Item = item;
        Tag = SortTag.NotMarked;
      }
    }
    
    public static IEnumerable TSort(this IEnumerable source, Func> dependencies)
    {
      TopologicalSorter.LastCyclicOrder.Clear();
    
      List allNodes = new List();
      HashSet sorted = new HashSet(StringComparer.OrdinalIgnoreCase);
    
      foreach (string item in source)
      {
        if (!allNodes.Where(n => string.Equals(n.Item, item, StringComparison.OrdinalIgnoreCase)).Any())
        {
          allNodes.Add(new ItemTag(item)); //don't insert duplicates
        }
        foreach (string dep in dependencies(item))
        {
          if (allNodes.Where(n => string.Equals(n.Item, dep, StringComparison.OrdinalIgnoreCase)).Any()) continue; //don't insert duplicates
          allNodes.Add(new ItemTag(dep));
        }
      }
    
      foreach (ItemTag tag in allNodes)
      {
        Visit(tag, allNodes, dependencies, sorted);
      }
    
      return sorted;
    }
    
    static void Visit(ItemTag tag, List allNodes, Func> dependencies, HashSet sorted)
    {
      if (tag.Tag == ItemTag.SortTag.TempMarked)
      {
        throw new GraphIsCyclicException();
      }
      else if (tag.Tag == ItemTag.SortTag.NotMarked)
      {
        tag.Tag = ItemTag.SortTag.TempMarked;
        LastCyclicOrder.Add(tag.Item);
    
        foreach (ItemTag dep in dependencies(tag.Item).Select(s => allNodes.Where(t => string.Equals(s, t.Item, StringComparison.OrdinalIgnoreCase)).First())) //get item tag which falls with used string
          Visit(dep, allNodes, dependencies, sorted);
    
        LastCyclicOrder.Remove(tag.Item);
        tag.Tag = ItemTag.SortTag.Marked;
        sorted.Add(tag.Item);
      }
    }
    }
    

提交回复
热议问题