C# Список различных типов объектов: лучший способ, чем Zip, для проверки равенства - PullRequest
1 голос
/ 13 июля 2020

У меня есть код, который работает прямо сейчас, эффективно выполняя поэлементное сравнение в лямбде для метода расширения Zip Linq, а затем проверяя любые неудачные совпадения, но я почти уверен, что должен быть более краткий и читаемый способ выполнения то же самое.

Я знаю, что могу реализовать EqualityComparer и использовать SequenceEqual, но мне не нравятся накладные расходы этого решения на одноразовые сравнения списков, подобные этому. Я готов согласиться с тем, что EqualityComparer - это правильное решение, но если есть альтернативы, мне бы хотелось их увидеть.

class Occurrence {
    DateTime Start;
    // More fields...
}

bool SameDates(List<Occurrence> occurrences, List<DateTime> selectedDates)
{
    if (occurrences.Count != selectedDates.Count)
            return false;

    // These three lines are the focus of the question
    var dateEqualList = occurrences.Zip(selectedDates, (a, b) => a.Start.Date == b.Date);
    if (dateEqualList.Contains(false))
        return false;

    return true;
}

Ответы [ 3 ]

2 голосов
/ 13 июля 2020

Я написал две разные альтернативы, вторая имеет гораздо лучшую производительность.

Альтернатива 1:

bool SameDates(List<Occurrence> occurrences, List<DateTime> selectedDates)
{
    if (occurrences.Count != selectedDates.Count)
        return false;

    var matchCount = occurrences.TakeWhile((d, i) => d.Start.Date == selectedDates[i].Date).Count();
    return matchCount == occurrences.Count;
}

Альтернатива 2:

bool SameDates2(List<Occurrence> occurrences, List<DateTime> selectedDates)
{
    if (occurrences.Count != selectedDates.Count)
        return false;

    for (var i = 0; i < occurrences.Count; i++)
    {
        if (occurrences[i].Start.Date != selectedDates[i].Date)
            return false;
    }

    return true;
}
1 голос
/ 14 июля 2020

Итак, вам нужен оператор LINQ, который проверяет, равно ли Occurrences[i].Start selectedDates[i] для всех индексов. Вы хотите остановиться, как только найдете неравную последовательность.

Я бы посоветовал сначала выбрать свойство Start, а затем проверить, соответствует ли полученная последовательность selectedDates:

List<Occurence> occurences = ...
List<DateTime> selectedDates = ...

var allDatesEqual = occurrences.Count == selectedDates.Count
                 && occurrences.Select(occurrence => occurence.Start)
                               .SequenceEqual(selectedDates);

Обычно SequenceEqual проверяет длину, если обе последовательности реализуют ICollection. Однако результат Select не реализует ICollection, поэтому для этой оптимизации вам нужно будет самостоятельно проверить счетчик.

Я читал, что вы заказываете последовательности перед началом сравнения. Если все даты уникальны, рассмотрите возможность использования HashSet<DateTime>

List<Occurence> occurences = ...
HashSet<DateTime> datesSet = new HashSet<DateTime>(selectedDates);

var allDatesEqual = datesSet.SetEquals(occurrences
                                       .Select(occurrence => occurence.Start));

SetEquals возвращает true, если они содержат точно такие же элементы, игнорируя порядок, поэтому set {A, B, C} равно set {B , C, A}, но не равно ни {A, B}, ни {A, B, C, D}

0 голосов
/ 13 июля 2020

Насколько большими будут эти списки? Можно ли выбрать другой подход и сделать что-то вроде этого:

class Occurrence {
    DateTime Start;
    // More fields...
}

bool SameDates(List<Occurrence> occurrences, List<DateTime> selectedDates)
{
    if (occurrences.Count != selectedDates.Count)
            return false;
    
    var dates1List = occurrences.Select(o => o.Start).Distinct();
    var dates1String = string.Join(",", dates1List.ToArray());
    
    var dates2List = selectedDates.Select(o => o.Start).Distinct();
    var dates2String = string.Join(",", dates2List.ToArray());
    
    return dates1String == dates2String;
}

Даже если это не сработает в точности или не соответствует вашей проблеме, возможно, это даст вам некоторые идеи.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...