/// <summary> /// Orders elements of a linearized directed graph in a dependency order, while preserving the original order /// between elements with no dependencies. /// </summary> public static IEnumerable <T> Order <T>( IEnumerable <T> itemsToOrder, TopologicalDependencyFunction <T> dependencyFunction) { if (itemsToOrder == null) { throw new ArgumentNullException(nameof(itemsToOrder)); } if (dependencyFunction == null) { throw new ArgumentNullException(nameof(dependencyFunction)); } var itemsToOrderList = itemsToOrder.ToList(); if (itemsToOrderList.Count < 2) { return(itemsToOrder); } int itemsToOrderCount = itemsToOrderList.Count; var graph = DependencyGraph <T> .TryCreate(itemsToOrderList, dependencyFunction, EqualityComparer <T> .Default); if (graph == null) { return(itemsToOrder); } Restart: for (int i = 0; i < itemsToOrderCount; ++i) { for (int j = 0; j < i; ++j) { if (graph.DoesXHaveDirectDependencyOnY(itemsToOrderList[j], itemsToOrderList[i])) { bool jDependsOnI = graph.DoesXHaveTransientDependencyOnY(itemsToOrderList[j], itemsToOrderList[i]); bool iDependsOnJ = graph.DoesXHaveTransientDependencyOnY(itemsToOrderList[i], itemsToOrderList[j]); bool circularDependency = jDependsOnI && iDependsOnJ; if (!circularDependency) { var t = itemsToOrderList[i]; itemsToOrderList.RemoveAt(i); itemsToOrderList.Insert(j, t); goto Restart; } } } } return(itemsToOrderList); }
public static DependencyGraph <T> TryCreate( IList <T> items, TopologicalDependencyFunction <T> dependencyFunction, IEqualityComparer <T> equalityComparer) { var graph = new DependencyGraph <T>(equalityComparer, items.Count); bool hasDependencies = false; for (int position = 0; position < items.Count; ++position) { var element = items[position]; if (!graph.Nodes.TryGetValue(element, out Node node)) { node = new Node(); graph.Nodes.Add(element, node); } foreach (var anotherElement in items) { if (equalityComparer.Equals(element, anotherElement)) { continue; } if (dependencyFunction(element, anotherElement)) { node.Children.Add(anotherElement); hasDependencies = true; } } } if (!hasDependencies) { return(null); } return(graph); }