У меня есть много кода, в котором я делаю что-то вроде этого
bool GetIsUnique(IEnumerable<T> values)
{
return values.Count() == values.Distinct().Count;
}
Есть ли более быстрый более удобный способ сделать это?
У меня есть много кода, в котором я делаю что-то вроде этого
bool GetIsUnique(IEnumerable<T> values)
{
return values.Count() == values.Distinct().Count;
}
Есть ли более быстрый более удобный способ сделать это?
Ваш метод должен повторять последовательность в два раза с несколькими потенциальными недостатками:
Count
, который должен каждый раз перебирать всю последовательность. Нет причин, по которым вам не следует начинать рано, как только вы знаете, что есть дублирующее значение.Следующий метод требует только повторения последовательности по порядку один раз и будет разорваться раньше, как только встретится какое-то повторяющееся значение:
bool GetIsUnique<T>(IEnumerable<T> values)
{
var set = new HashSet<T>();
foreach (T item in values)
{
if (!set.Add(item))
return false;
}
return true;
}
Я бы сделал это хорошим методом расширения
public static bool IsUnique<T>(this IEnumerable<T> list)
{
var hs = new HashSet<T>();
return list.All(hs.Add);
}
Проверяет, что все элементы могут быть добавлены в HashSet.
Я думаю, это зависит от того, что вы хотите сделать, если есть уникальные значения. @Jamiec или ответ @LukeH - отличные ответы и, вероятно, лучше всего подходят для чистой скорости, но он не может сказать вам, где проблемы.
Вы также можете рассмотреть что-то вроде
var group = values.GroupBy(x => x);
return group.Any(g => g.Count() > 1);
На самом деле это хуже, чем реализация HashSet
. Но если вы держите эту группу вокруг, вы можете найти, какие элементы дублируются.
var group = values.GroupBy(x => x);
return group.Where(g => g.Count() > 1);
или
var group = values.GroupBy(x => x);
return group.Where(g => g.Count() > 1).Select(g => g.Key);
Размышление об этом с помощью GroupBy
позволяет вам открывать свои возможности для того, что делать дальше. Но если все, о чем вы заботитесь, это знать, являются ли все значения уникальными, я бы пошел с HashSet
Вы бы делали две петли через данные для выше - один раз, чтобы получить счет, один раз, чтобы получить отчетный счет. Особенно плохо, если первые два предмета идентичны! Попробуйте что-то вроде этого:
bool GetIsUnique<T>(IEnumerable<T> values)
{
HashSet<T> hashSet = new HashSet<T>();
foreach(var value in values)
{
if (hashSet.Contains(value))
{
return false;
}
hashSet.Add(value);
}
return true;
}
Этот будет завершен, как только он найдет дубликат. Очевидно, что на скорости поиска хэша, но учитывая, что Distinct использует набор внутри, я бы все еще ожидал, что он будет быстрее.
Два основных правила:
Другие методы будут быстрее (они будут замыкаться на короткое замыкание при обнаружении повторяющегося значения, возвращая false), но я все равно буду придерживаться вашей версии, если бы это был мой код.
Быстрый поиск первого дубликата, если он есть, следующий:
public static bool TryFindFirstDuplicate<T>(this IEnumerable<T> source, out T duplicate)
{
var set = new HashSet<T>();
foreach (var item in source)
{
if (!set.Add(item))
{
duplicate = item;
return true;
}
}
duplicate = default(T);
return false;
}