Advertisement
Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using LINQ.Lessons.Contract;
- using MoreLinq;
- namespace LINQ.Lessons
- {
- public static class FamilyTreeExtensions
- {
- public static Person GetMotherOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- return persons.FirstOrDefault(x => x.Name.Equals(person.MotherName, StringComparison.InvariantCultureIgnoreCase));
- }
- public static Person GetFatherOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- return persons.FirstOrDefault(x => x.Name.Equals(person.FatherName, StringComparison.InvariantCultureIgnoreCase));
- }
- public static IEnumerable<Person> GetGrandMothersOrNull(this Person person, ICollection<Person> persons)
- {
- yield return person.GetMotherOrNull(persons)
- .GetMotherOrNull(persons);
- yield return person.GetFatherOrNull(persons)
- .GetMotherOrNull(persons);
- }
- public static IEnumerable<Person> GetGrandFatherOrNull(this Person person, ICollection<Person> persons)
- {
- yield return person.GetFatherOrNull(persons)
- .GetFatherOrNull(persons);
- yield return person.GetMotherOrNull(persons)
- .GetFatherOrNull(persons);
- }
- public static IEnumerable<Person> GetChildrenOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- var filterFunction = person.Sex == Sex.Male
- ? new Func<Person, bool>(p => p.FatherName?.Equals(person.Name) == true)
- : p => p.MotherName?.Equals(person.Name) == true;
- return persons.Where(filterFunction);
- }
- public static IEnumerable<Person> GetBloodBrothersOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- var parent = person.GetMotherOrNull(persons) ?? person.GetFatherOrNull(persons);
- return parent
- .GetChildrenOrNull(persons)
- .Where(p => string.Equals(p.FatherName, person.FatherName)
- && string.Equals(p.MotherName, person.MotherName)
- && p.Sex == Sex.Male
- && !string.Equals(p.Name, person.Name));
- }
- public static IEnumerable<Person> GetBloodSistersOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- var parent = person.GetMotherOrNull(persons) ?? person.GetFatherOrNull(persons);
- return parent
- .GetChildrenOrNull(persons)
- .Where(p => string.Equals(p.FatherName, person.FatherName)
- && string.Equals(p.MotherName, person.MotherName)
- && p.Sex == Sex.Female
- && !string.Equals(p.Name, person.Name));
- }
- public static IEnumerable<Person> GetBrothersByFatherLoversOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- return person.GetFatherOrNull(persons)
- .GetChildrenOrNull(persons)
- .Where(p => !string.Equals(p.MotherName, person.MotherName) && p.Sex == Sex.Male && !string.Equals(p.Name, person.Name));
- }
- public static IEnumerable<Person> GetBrothersByMotherLoversOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- return null;
- return person.GetFatherOrNull(persons)
- .GetChildrenOrNull(persons)
- .Where(p => !string.Equals(p.FatherName, person.FatherName) && p.Sex == Sex.Male && !string.Equals(p.Name, person.Name));
- }
- public static IEnumerable<Person> GetAncestorsOrNull(this Person person, ICollection<Person> persons)
- {
- var mother = person.GetMotherOrNull(persons);
- if (mother != null)
- {
- yield return mother;
- foreach (var ancestor in mother.GetAncestorsOrNull(persons))
- {
- yield return ancestor;
- }
- }
- var father = person.GetFatherOrNull(persons);
- if (father != null)
- {
- yield return father;
- foreach (var ancestor in father.GetAncestorsOrNull(persons))
- {
- yield return ancestor;
- }
- }
- }
- public static IEnumerable<Person> GetDescendantsOrNull(this Person person, ICollection<Person> persons)
- {
- if (person == null)
- yield return null;
- var children = person.GetChildrenOrNull(persons);
- if (children != null)
- {
- foreach (var child in children)
- {
- yield return child;
- foreach (var descendant in child.GetDescendantsOrNull(persons))
- {
- yield return descendant;
- }
- }
- }
- }
- public static IEnumerable<Person> GetRelativesOrNull(this Person person, ICollection<Person> persons)
- {
- var ancestorsOrNull = person.GetAncestorsOrNull(persons);
- if (ancestorsOrNull == null)
- return null;
- var ancestorsAndPerson = ancestorsOrNull
- .Concat(new[] {person})
- .ToList();
- return ancestorsAndPerson
- .Select(p => p.GetDescendantsOrNull(persons))
- .SelectMany(x => x)
- .Concat(ancestorsAndPerson)
- .Except(new[] {person})
- .Distinct();
- }
- //todo поправить
- public static IEnumerable<Person> GetRelatives(this Person person, ICollection<Person> persons)
- {
- var ancestors = person?.GetAncestorsOrNull(persons);
- if (ancestors == null)
- return null;
- return ancestors.SelectMany(x => x.GetDescendantsOrNull(persons))
- .Distinct()
- .Except(new[] {person});
- }
- public static IEnumerable<Person> GetTree(this Person person,
- ICollection<Person> persons,
- HashSet<Person> visited = null)
- {
- if (visited == null)
- visited = new HashSet<Person>();
- if (person == null || visited.Contains(person))
- yield break;
- yield return person;
- visited.Add(person);
- var childrenOrNull = person.GetChildrenOrNull(persons);
- if (childrenOrNull == null)
- yield break;
- foreach (var child in childrenOrNull)
- {
- foreach (var result in child.GetTree(persons, visited))
- yield return result;
- }
- var fatherOrNull = person.GetFatherOrNull(persons);
- if (fatherOrNull == null)
- yield break;
- foreach (var result in fatherOrNull.GetTree(persons, visited))
- yield return result;
- var motherOrNull = person.GetMotherOrNull(persons);
- if (motherOrNull == null)
- yield break;
- foreach (var result in motherOrNull.GetTree(persons, visited))
- yield return result;
- }
- public static IEnumerable<PersonWithLvl> GetTreeWithLevels(this Person person,
- ICollection<Person> persons,
- HashSet<Person> visited = null,
- int currentLvl = 0)
- {
- visited = visited ?? new HashSet<Person>();
- if (person == null || visited.Contains(person))
- yield break;
- yield return new PersonWithLvl(person, currentLvl);
- visited.Add(person);
- var childrenOrNull = person.GetChildrenOrNull(persons);
- foreach (var child in childrenOrNull)
- {
- var lvlUp = currentLvl + 1;
- var childResults = child.GetTreeWithLevels(persons, visited, currentLvl: lvlUp);
- foreach (var result in childResults)
- yield return result;
- }
- var fatherOrNull = person.GetFatherOrNull(persons);
- var lvlDown = currentLvl - 1;
- var fatherResults = fatherOrNull.GetTreeWithLevels(persons, visited, currentLvl: lvlDown);
- foreach (var result in fatherResults)
- yield return result;
- var motherOrNull = person.GetMotherOrNull(persons);
- var motherResults = motherOrNull.GetTreeWithLevels(persons, visited, currentLvl: lvlDown);
- foreach (var result in motherResults)
- yield return result;
- }
- public static IEnumerable<IEnumerable<Person>> GetTrees(ICollection<Person> persons)
- {
- var visited = new HashSet<Person>();
- while (visited.Count != persons.Count)
- {
- var firstNotVisited = persons.FirstOrDefault(p => !visited.Contains(p));
- var tree = firstNotVisited.GetTree(persons).ToList();
- yield return tree;
- tree.ForEach(x => visited.Add(x));
- }
- }
- public static IEnumerable<IEnumerable<PersonWithLvl>> GetTreesWithLvl(this ICollection<Person> persons)
- {
- var visited = new HashSet<Person>();
- while (visited.Count != persons.Count)
- {
- var firstNotVisited = persons.FirstOrDefault(p => !visited.Contains(p));
- var tree = firstNotVisited.GetTreeWithLevels(persons).ToList();
- yield return tree;
- tree.ForEach(x => visited.Add(x.Person));
- }
- }
- public static bool IsInOneGenerationWith(this Person person1, Person person2, ICollection<Person> persons)
- {
- var person2WithLvlOrNull = person1.GetTreeWithLevels(persons)
- .FirstOrDefault(x => x.Equals(person2));
- if (person2WithLvlOrNull == null || person2WithLvlOrNull.Level == 0)
- return false;
- return true;
- }
- public static Person GetNearestCommonAncestorOrNull(this Person person1, Person person2, ICollection<Person> persons)
- {
- var ancestorsForPerson1 = person1.GetAncestorsOrNull(persons);
- if (ancestorsForPerson1 == null)
- return null;
- var ancestorsForPerson2 = person2.GetAncestorsOrNull(persons);
- if (ancestorsForPerson2 == null)
- return null;
- var ancestorsForPerson1Set = new HashSet<Person>(ancestorsForPerson1);
- var treeWithLevels = person2.GetTreeWithLevels(persons);
- var ancestorsIntersection = treeWithLevels?
- .Where(x => ancestorsForPerson1Set.Contains(x.Person))
- .ToList();
- if (ancestorsIntersection == null || ancestorsIntersection.Count == 0)
- return null;
- return ancestorsIntersection.OrderBy(x => x.Level)
- .First()
- .Person;
- }
- public static void PrintTrees(this Person[] persons)
- {
- foreach (var treeWithLvl in persons.GetTreesWithLvl())
- {
- PrintTree(treeWithLvl);
- }
- }
- private static void PrintTree(this IEnumerable<PersonWithLvl> persons)
- {
- var personWithLvls = persons as PersonWithLvl[] ?? persons.ToArray();
- var sortedPersons = personWithLvls.OrderBy(x => x.Level)
- .ToArray();
- var lvls = personWithLvls.Select(x => x.Level)
- .OrderBy(x => x)
- .Distinct()
- .ToArray();
- var groupByLvl = personWithLvls.ToLookup(x => x.Level);
- if (sortedPersons.Length == 0)
- return;
- var minTreeLvl = Math.Abs(lvls[0]);
- foreach (var lvl in lvls)
- {
- var generation = groupByLvl[lvl];
- var tabsCount = lvl + minTreeLvl;
- var tabs = new string('\t', tabsCount);
- Console.WriteLine($"Gen {lvl}->{tabs}{string.Join("|", generation.Select(x => x.Person.Name))}");
- }
- }
- public static IEnumerable<Person> FindBestPath(this Person fromPerson,
- Person toPerson,
- ICollection<Person> persons)
- {
- var path = new Dictionary<Person, Person>();
- var queue = new Queue<Person>();
- queue.Enqueue(toPerson);
- path[toPerson] = null;
- while (queue.Count != 0)
- {
- var person = queue.Dequeue();
- var nextPersons = person.GetChildrenOrNull(persons)
- .Concat(new[] {person.GetFatherOrNull(persons), person.GetMotherOrNull(persons)})
- .Where(p => p != null && !path.ContainsKey(p));
- foreach (var nextPerson in nextPersons)
- {
- queue.Enqueue(nextPerson);
- path[nextPerson] = person;
- }
- if (path.ContainsKey(fromPerson))
- break;
- }
- yield return fromPerson;
- while (fromPerson != null && path[fromPerson] != null)
- yield return fromPerson = path[fromPerson];
- }
- //todo свойствО (ударение на последнюю О). цепочка общих родственников
- //todo находятся ли два человека в одном поколении.
- //todo 2 человека, найти самого ближайшего общего предка
- //todo вывод деревьев по поколениям
- //todo 2 человека, найти самого ближайшего общего предка
- //todo для двух свояков найти самую короткую цепочку родственников
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement