public static IEnumerable <IEnumerable <T> > TopologySortDesc <T> ( this IEnumerable <T> source, Func <T, IEnumerable <T> > getDependencies, Func <IEnumerable <T>, IEnumerable <T> > subSort, TopologySortMissingDependencyBehavior missingDependencies ) { return(TopologySort(source, getDependencies, subSort, missingDependencies).Reverse()); }
public void CalculateDependencies(Dictionary <object, Node <T> > nodes, TopologySortMissingDependencyBehavior missingDependencies) { _dependencies = new HashSet <Node <T> >(); foreach (T dependency in _getDependencies(Content)) { Node <T> node; if (!nodes.TryGetValue(dependency, out node)) { switch (missingDependencies) { case TopologySortMissingDependencyBehavior.Ignore: node = null; break; case TopologySortMissingDependencyBehavior.Respect: node = new Node <T> (dependency, _getDependencies, false); break; case TopologySortMissingDependencyBehavior.Include: node = new Node <T> (dependency, _getDependencies, true); break; default: throw new ArgumentOutOfRangeException("missingDependencies"); } if (node != null) { nodes.Add(node.Content, node); node.CalculateDependencies(nodes, missingDependencies); } } if (node != null) { AddDependency(node); } } }
/// <summary> /// Sorts the objects given in <paramref name="source"/> using a topology-sort algorithm. /// The graph structure is defined by the <paramref name="getDependencies"/> delegate which should supply the /// dependencies for each object to sort, i.e. the edges of the graph. /// The <paramref name="subSort"/> delegate, if supplied, specifies how objects will be sorted whose sort-order cannot /// be determined by the graph structure. /// </summary> /// <typeparam name="T"></typeparam> /// <param name="source"></param> /// <param name="getDependencies"></param> /// <param name="subSort"></param> /// <param name="missingDependencies"> /// Controls how to process dependencies which were not included in the original <paramref name="source"/>. /// See <see cref="TopologySortMissingDependencyBehavior"/>. /// </param> /// <returns>Returns the sorted items of the topology grouped by their hierarchy level starting with the leave-nodes.</returns> public static IEnumerable <IEnumerable <T> > TopologySort <T> ( this IEnumerable <T> source, Func <T, IEnumerable <T> > getDependencies, Func <IEnumerable <T>, IEnumerable <T> > subSort, TopologySortMissingDependencyBehavior missingDependencies ) { ArgumentUtility.CheckNotNull("source", source); ArgumentUtility.CheckNotNull("getDependencies", getDependencies); var unsorted = source.Select(content => new Node <T> (content, getDependencies, true)).ToList(); Dictionary <object, Node <T> > nodes; try { nodes = unsorted.ToDictionary(node => (object)node.Content); } catch (ArgumentException e) { throw new InvalidOperationException("elements to topology-sort are not unique or some element is null.", e); } unsorted.ForEach(node => node.CalculateDependencies(nodes, missingDependencies)); if (missingDependencies == TopologySortMissingDependencyBehavior.Include) { unsorted = nodes.Values.Where(node => node.Included).ToList(); } var sorted = new List <IEnumerable <T> >(); while (unsorted.Count > 0) { var unreferred = new List <Node <T> >(); var toBeSortedNext = new List <Node <T> >(); foreach (var node in unsorted) { if (node.ReferrerCount == 0) { unreferred.Add(node); } else { toBeSortedNext.Add(node); } } if (unreferred.Count == 0) { throw new InvalidOperationException("Cyclic dependency detected - cannot perform topology sort"); } unsorted = toBeSortedNext; var unreferredContents = unreferred.Select(node => node.DropDependencies().Content); if (subSort != null) { unreferredContents = subSort(unreferredContents); } sorted.Add(unreferredContents.ToArray()); } return(sorted); }