private static void VerifyAllSuffixes(string[] strings, IEnumerable <Suffix> result) { var expectedSuffixes = new List <string>(); var expectedSources = new LazyDictionary <string, List <int> >(_ => new List <int>()); for (var i = 0; i < strings.Length; ++i) { var s = strings[i]; for (var j = 0; j < s.Length; ++j) { var suffix = s.Substring(j); expectedSuffixes.Add(suffix); expectedSources[suffix].Add(i); } } expectedSuffixes.Sort(); var suffixes = result.ToList(); Assert.That(suffixes.Select(_ => _.Value).ToList(), Is.EqualTo(expectedSuffixes)); var grouped = suffixes.Select(_ => new { value = _.Value, source = _.SourceIndex }) .GroupBy(_ => _.value).ToDictionary(_ => _.Key, _ => _.Select(v => v.source).OrderBy(v => v).ToList()); foreach (var v in grouped) { Assert.That(v.Value, Is.EqualTo(expectedSources[v.Key])); } }
private static void TestStartingWith(string[] strings) { var prefixes = new HashSet <string>(); var st = new SuffixTree(); foreach (var s in strings) { st.Add(s); for (var i = 0; i < s.Length; ++i) { for (var j = i + 1; j <= s.Length; ++j) { prefixes.Add(s.Substring(i, j - i)); } } } st.Compact(); foreach (var prefix in prefixes) { var expectedSuffixes = new List <string>(); var expectedSources = new LazyDictionary <string, List <int> >(_ => new List <int>()); for (var i = 0; i < strings.Length; ++i) { var s = strings[i]; var pos = 0; for (;;) { pos = s.IndexOf(prefix, pos); if (pos == -1) { break; } var suffix = s.Substring(pos); expectedSuffixes.Add(suffix); expectedSources[suffix].Add(i); ++pos; } } expectedSuffixes.Sort(); var suffixes = st.StartingWith(prefix).ToList(); Assert.That(suffixes.Select(_ => _.Value).ToList(), Is.EqualTo(expectedSuffixes)); var grouped = suffixes.Select(_ => new { value = _.Value, source = _.SourceIndex }) .GroupBy(_ => _.value).ToDictionary(_ => _.Key, _ => _.Select(v => v.source).OrderBy(v => v).ToList()); foreach (var v in grouped) { Assert.That(v.Value, Is.EqualTo(expectedSources[v.Key])); } } Assert.That(st.StartingWith("@").Count(), Is.EqualTo(0)); VerifyAllSuffixes(strings, st.StartingWith(string.Empty)); }
public static IEnumerable <T[]> GroupTopoSort <T>( this ICollection <T> source, [InstantHandle] Func <T, IEnumerable <T> > dependsOnGetter, IEqualityComparer <T> equalityComparer) where T : notnull { Code.NotNull(source, nameof(source)); Code.NotNull(dependsOnGetter, nameof(dependsOnGetter)); Code.NotNull(equalityComparer, nameof(equalityComparer)); // Fast path if (source.Count == 0) { yield break; } var dependants = LazyDictionary.Create( _ => new List <T>(), equalityComparer, false); var workArray = new int[source.Count]; var indices = new Dictionary <T, int>(equalityComparer); var level = new List <T>(); foreach (var(index, item) in source.WithIndex()) { var count = 0; foreach (var dep in dependsOnGetter(item)) { dependants[dep].Add(item); count++; } if (count == 0) { level.Add(item); } else { workArray[index] = count; } indices.Add(item, index); } if (level.Count == 0) { throw CycleException(nameof(source)); } // Fast path if (level.Count == workArray.Length) { yield return(level.ToArray()); yield break; } var pendingCount = workArray.Length; while (true) { var nextLevel = Lazy.Create(() => new List <T>(), false); foreach (var item in level) { foreach (var dep in dependants[item]) { var pending = --workArray[indices[dep]]; if (pending == 0) { nextLevel.Value.Add(dep); } } } yield return(level.ToArray()); pendingCount -= level.Count; if (pendingCount == 0) { yield break; } if (!nextLevel.IsValueCreated) { throw CycleException(nameof(source)); } level = nextLevel.Value; } }