На собеседованиях часто просят решить следующую задачу. Написать метод, который будет возвращать true, если в коллекции (массиве) есть хотя-бы один повторяющий элемент. Метод должен уметь работать с любыми типами данных (например int, string, MyClass). Причем ограничений по версии .NET нам не ставят, поэтому мы с легкостью можем использовать технологию LINQ. Данную задачу можно решить двумя путями:
- посчитать сколько всего элементов в коллекции и посчитать сколько уникальных элементов, если количество не совпадает, то возвращать true (используем Distinct)
- сгруппировать элементы коллекции и если хотя бы в одной группе количество элементов больше одного, то вернуть true (используем GroupBy)
Давайте напишем класс, который будет реализовывать четыре метода один дженерик один частный на каждый из вариантов решения
public static class CollectionExtensions { /// <summary> /// Решение для коллекции чисел с помощью Distinct /// </summary> /// <param name="collection"></param> /// <returns></returns> public static bool HasDuplicatesUseDistinct(this IEnumerable<int> collection) { return collection.Count() != collection.Distinct().Count(); } /// <summary> /// Решение для коллекции чисел с помощью GroupBy /// </summary> /// <param name="collection"></param> /// <returns></returns> public static bool HasDuplicatesUseGroupBy(this IEnumerable<int> collection) { return collection .GroupBy(x => x) .Any(x => x.Count() > 1); } /// <summary> /// Generic решение с помощью Distinct. Требует дополнительного параметра для классов и структур /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <param name="comparer"></param> /// <returns></returns> public static bool HasDuplicatesUseDistinctGeneric<T>(this IEnumerable<T> collection, IEqualityComparer<T> comparer = null) { return collection.Count() != (comparer == null ? collection.Distinct().Count() : collection.Distinct(comparer).Count()); } /// <summary> /// Generic решение с помощью Distinct. Требует дополнительного параметра для классов и структур /// </summary> /// <typeparam name="T"></typeparam> /// <param name="collection"></param> /// <returns></returns> public static bool HasDuplicatesUseGroupByGeneric<T>(this IEnumerable<T> collection, IEqualityComparer<T> comparer = null) { return collection .GroupBy(x => x, comparer) .Any(x => x.Count() > 1); } }
Вот-так можно пользоваться этими расширениями
int[] numbers = new int[] { 1, 2, 3, 2 }; string[] words = new string[] { "tree", "car", "house", "developer", "car" }; Car[] cars = new Car[] { new Car("bmw", 92), new Car("daewoo", 54), new Car("bMw", 92) }; Console.WriteLine(numbers.HasDuplicatesUseDistinct()); Console.WriteLine(numbers.HasDuplicatesUseGroupBy()); Console.WriteLine(cars.HasDuplicatesUseDistinctGeneric(new CarComparer())); Console.WriteLine(cars.HasDuplicatesUseGroupByGeneric(new CarComparer())); Console.WriteLine(words.HasDuplicatesUseDistinctGeneric()); Console.WriteLine(words.HasDuplicatesUseGroupByGeneric());
Готовое решение доступно по нажатию "скачать бесплатно". Проект использует Visual Studio 2015
dmytro