nebiam Ответов: 2

LINQ, которая, кроме (), используя список<типа datetime&ГТ;[]


// create lists of potential start and end times in 15 min intervals from 8am-6pm (this results in two lists of datetimes). 
var initialTimes = InitialTimeList(15); 

// create lists of booked times (this results in two lists of datetimes) in 15 min intervals
var bookedTimes = BookedTimeList(bookedtimes, 15);

// remove duplicates from the initial time list
var availableTimes = initialTimes.Except(bookedTimes);



Проблема в том, что он возвращает сравниваемые списки, но не удаляет дубликаты... Я не уверен, что linq может сравнивать массив списков? Любые предложения будут очень признательны. Заранее спасибо!!!

Что я уже пробовал:

Я пробовал использовать метод except с одним списком, и он работает просто отлично. Он возвращает начальный список времени за вычетом забронированного времени. Только в массиве он просто возвращает начальный список, не исключая забронированное время.

David_Wimbley

Вы хотите сказать, что вам просто нужен список элементов, которых нет по дате и времени в другом списке?

Пример: список 1 - > 1,2,3,4
Список 2- & gt; 2,4,5,6

Ваш результирующий набор при сравнении списка 2 со Списком 1 будет равен 5,6. Это верно?

nebiam

Да. Это звучит просто, но это то, что происходит. Например..
Список 1 - > 1234567
Список 2 - > 123

Результат должен быть 4567, но вместо этого он показывает полные результаты списка 1.

Вспоминая его в массиве, хотя.. Итак, у меня есть два списка, оба с начальным и конечным временем..

Maciej Los

Не могли бы вы быть так любезны и предоставить более подробную информацию о ваших списках? Примеры данных могут помочь нам предложить вам решение.

2 Ответов

Рейтинг:
17

Matt T Heffron

Решение Дэвида имеет фундаментальную неэффективность. Он повторяет через newbooks сбор для каждого члена oldbooks. Это делает его O (n*m) где n является ли граф newbooks и m является ли граф oldbooks.

Ваша первая попытка с .Except() был почти правильно!

Использование класса книг Дэвида в качестве примера:
Вам нужно было либо переопределить метод Equals () книг:

public class Books
{
  public string Name { get; set; }
  public DateTime PublishDate { get; set; }

  public override bool Equals(object obj)
  {
    Books other = obj as Books;
    return other != null && this.PublishDate == other.PublishDate;
  }

  public override int GetHashCode()
  {
    return PublishDate.GetHashCode();
  }
}

// Then get the difference with:
var diff = oldbooks.Except(newbooks);

(Если вы переопределите Equals очень важно также переопределить GetHashCode.)
Это означает, что все сравнения Books объекты будут рассматривать только PublishDate, и вы не могли бы сделать это для другого сравнения позже.

Более гибким способом было бы реализовать класс компаратора:
public class Books
{
  public string Name { get; set; }
  public DateTime PublishDate { get; set; }
}

public class BooksDateComparer : IEqualityComparer<Books>
{
  public bool Equals(Books x, Books y)
  {
    //Check whether the compared objects reference the same data.
    if (Object.ReferenceEquals(x, y))
      return true;

    //Check whether any of the compared objects is null.
    if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
      return false;
    // compare the dates
    return x.PublishDate == y.PublishDate;
  }

  public int GetHashCode(Books obj)
  {
    //Check whether the object is null
    if (Object.ReferenceEquals(obj, null))
      return 0;
    return obj.PublishDate.GetHashCode();
  }
}

// This way get the difference with:
var diff = oldbooks.Except(newbooks, new BooksDateComparer());

Кроме того, просто для уточнения: Linq работает точно так же на массивах, как это происходит на List<T>. Ему нужна только коллекция для реализации IEnumerable<T>.


David_Wimbley

Славно, спасибо, что уделили мне внимание. +5

Maciej Los

5ед!
Вот о чем я говорил!

Рейтинг:
11

David_Wimbley

Поэтому, поскольку я не знаю вашего типа данных, я создал класс под названием Books, чтобы продемонстрировать сложный тип данных для этого сравнения.

public class Books
{
    public string Name { get; set; }
    public DateTime PublishDate { get; set; }
}


После использования

var newbooks = new List<Books>();
            var oldbooks = new List<books>();

            newbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 1, 1) });
            newbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 2, 1) });
            newbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 3, 1) });

            oldbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 1, 1) });
            oldbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 2, 1) });
            oldbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 3, 1) });
            oldbooks.Add(new Books { Name = "", PublishDate = new DateTime(2016, 4, 1) });

            var diff = oldbooks.Where(m=> !newbooks.Select(x=>x.PublishDate).Contains(m.PublishDate));

            foreach (var item in diff)
            {
                Console.WriteLine("Book name {0} - Publish Date {1}", item.Name, item.PublishDate);
            }


Выход

Book name  - Publish Date 4/1/2016 12:00:00 AM


Таким образом, чтобы получить элементы, не входящие в оба списка, вы бы использовали !.Содержит Для сравнения.


nebiam

Тип данных-это список<типа datetime&ГТ;[] timeList = новый список<типа datetime&ГТ;[2];

David_Wimbley

Ваш тип данных не имеет смысла. Это не синтаксис для объявления списка.

В любом случае, если вы использовали массив, вы можете преобразовать свой массив в список с помощью.ToList () и используйте тот же метод, что и в моем ответе, чтобы сравнить и получить разницу.

Maciej Los

Это частично верно для базового решения. Для более продвинутых решений OP должен реализовать метод Equals.