63 lines
1.8 KiB
C#
63 lines
1.8 KiB
C#
using System;
|
|
using System.Collections.Generic;
|
|
using System.Text;
|
|
|
|
namespace DanieleMarotta.RiversongCodeShowcase
|
|
{
|
|
public class TopologicalSort<T>
|
|
{
|
|
private HashSet<T> _currentDependencies;
|
|
|
|
private HashSet<T> _closed;
|
|
|
|
public TopologicalSort(IEqualityComparer<T> comparer)
|
|
{
|
|
_currentDependencies = new HashSet<T>(comparer);
|
|
_closed = new HashSet<T>(comparer);
|
|
}
|
|
|
|
public TopologicalSort() : this(EqualityComparer<T>.Default)
|
|
{
|
|
}
|
|
|
|
public static TopologicalSort<T> Default { get; } = new();
|
|
|
|
public IEnumerable<T> Sort(IEnumerable<T> source, Func<T, List<T>> dependenciesGetter, ICollection<T> sorted = null)
|
|
{
|
|
sorted ??= new List<T>();
|
|
|
|
try
|
|
{
|
|
foreach (var item in source) Visit(item, dependenciesGetter, sorted);
|
|
}
|
|
finally
|
|
{
|
|
_currentDependencies.Clear();
|
|
_closed.Clear();
|
|
}
|
|
|
|
return sorted;
|
|
}
|
|
|
|
private void Visit(T item, Func<T, List<T>> dependenciesGetter, ICollection<T> sorted)
|
|
{
|
|
if (!_currentDependencies.Add(item))
|
|
{
|
|
var ex = new StringBuilder();
|
|
ex.AppendLine(item.ToString());
|
|
foreach (var dependency in _currentDependencies) ex.AppendLine(dependency.ToString());
|
|
|
|
throw new InvalidOperationException(ex.ToString());
|
|
}
|
|
|
|
var dependencies = dependenciesGetter.Invoke(item);
|
|
if (dependencies != null)
|
|
foreach (var dependency in dependencies)
|
|
Visit(dependency, dependenciesGetter, sorted);
|
|
|
|
_currentDependencies.Remove(item);
|
|
|
|
if (_closed.Add(item)) sorted.Add(item);
|
|
}
|
|
}
|
|
} |