Могу ли я использовать LINQ для проверки того, имеют ли объекты в списке уникальный идентификатор?

Скажем, у меня есть список, содержащий такие объекты, как этот:

public class Person
{
    private string _name; 
    private string _id;
    private int _age;

    public Person 
    {
    }

    // Accessors
}

public class ManipulatePerson
{
    Person person = new Person();
    List<Person> personList = new List<Person>;

    // Assign values

    private void PopulateList();
    {
        // Loop 
        personList.Add(person);

        // Check if every Person has a unique ID
    }
}

и я хотел проверить, что у каждого человека был уникальный идентификатор. Я хотел бы вернуть логическое значение true/false в зависимости от того, являются ли идентификаторы уникальными. Можно ли достичь этого с помощью LINQ?

+5
источник поделиться
4 ответа

Обратите внимание, что вы даже можете использовать непосредственно HashSet<>:

var hs = new HashSet<string>();
bool areAllPeopleUnique = personList.All(x => hs.Add(x.Id));

(и это код, который я обычно использую)

Это имеет то преимущество, что в лучшем случае (наличие некоторых дубликатов) он остановится, прежде чем анализировать всю коллекцию personList.

+4
источник

Я бы использовал Distinct, а затем, например, проверил против count:

bool bAreAllPeopleUnique = (personList.Distinct(p => p.ID).Count == personList.Count);

Однако, как прокомментировал @Ian, вам нужно добавить свойство в класс Person, чтобы вы могли получить доступ к Id так:

public string ID
{
    get { return _id; }
}

"Лучше" реализовать это было бы добавить такой метод:

private bool AreAllPeopleUnique(IEnumerable<Person> people)
{
    return (personList.Distinct(p => p.ID).Count == personList.Count);
}

ПРИМЕЧАНИЕ. Метод принимает IEnumerable не список, поэтому любой класс, реализующий этот интерфейс, может использовать этот метод.

+6
источник

Один из лучших способов сделать это - переопределить Equals и GetHashCode и реализовать IEquatable<T>:

public class Person : IEquatable<Person>
{
     public string Id { get; set; }

     public override bool Equals(object some) => Equals(some as Person);
     public override bool GetHashCode() => Id != null ? Id.GetHashCode() : 0;
     public bool Equals(Person person) => person != null && person.UniqueId == UniqueId;
}

Теперь вы можете использовать HashSet<T> для хранения уникальных объектов, и вы не сможете хранить дубликаты. Кроме того, если вы попытаетесь добавить дублированный элемент, Add вернет false.

ПРИМЕЧАНИЕ. Мои переопределения IEquatable<T> и Equals/GetHashCode очень просты, но эта примерная реализация должна дать вам хороший совет о том, как элегантно обрабатывать ваш сценарий.

Вы можете проверить этот Q & A, чтобы получить представление о том, как реализовать GetHashCode Каков наилучший алгоритм для переопределенного System.Object.GetHashCode?

Возможно, этот другой Q & A может быть интересен для вас: Почему важно переопределить GetHashCode, когда метод Equals переопределен?

+1
источник

Вы можете использовать GroupBy для получения уникальных элементов:

var result = personList.GroupBy(p=> p.Id)
                   .Select(grp => grp.First())
                   .ToList();
0
источник

Посмотрите другие вопросы по меткам или Задайте вопрос