List <List <int>> Метод Remove () - PullRequest
       30

List <List <int>> Метод Remove ()

4 голосов
/ 10 апреля 2011

Я хотел бы использовать метод Remove () в списке списков, но он не работает для меня.
Простой пример должен сказать все:

List<List<int>> list = new List<List<int>>();
list.Add(new List<int> { 0, 1, 2 });
list.Add(new List<int> { 1, 2 });
list.Add(new List<int> { 4 });
list.Add(new List<int> { 0, 1, });

list.Remove(new List<int> { 1, 2 });

Если я использую RemoveAt (1)он работает нормально, но Remove () нет.
Очевидно, что этот код возвращает false:

List<int> l1 = new List<int>();
List<int> l2 = new List<int>();
l1.Add(1);
l2.Add(1);

bool b1 = l1 == l2; // returns False
bool b2 = l1.Equals(l2); // returns False too

Так что мне кажется, что я не могу просто сравнить два списка или даже массива.Я могу использовать циклы вместо Remove (), но должен быть более простой способ.

Заранее спасибо.

Ответы [ 6 ]

11 голосов
/ 10 апреля 2011

Проблема в том, что List<T> не переопределяет Equals и GetHashCode, и это то, что List<T> будет использовать при попытке найти предмет. (Фактически, он будет использовать компаратор равенства по умолчанию, что означает, что он будет использовать реализацию IEquatable<T>, если объект реализует его, и при необходимости вернется к object.Equals / GetHashCode). Equals вернет false, когда вы пытаетесь удалить другой объект, и реализация по умолчанию - просто сравнить ссылки.

По сути, вам нужно написать метод для сравнения двух списков на равенство и использовать его, чтобы найти индекс записи, которую вы хотите удалить. Затем вы удалите по индексу (используя RemoveAt). РЕДАКТИРОВАТЬ: Как отмечено, Enumerable.SequenceEqual может быть использован для сравнения списков. Это не так эффективно, как могло бы быть из-за того, что изначально не проверяли, равны ли значения, когда их можно легко вычислить. Кроме того, если вам нужно только сравнить значения List<int>, вы можете избежать вызова виртуального метода для сравнения равенства.

Другая альтернатива - избегать использования List<List<int>>, во-первых - используйте List<SomeCustomType>, где SomeCustomType включает a List<int>. Затем вы можете реализовать IEquatable<T> в такого типа . Обратите внимание, что это также может позволить вам инкапсулировать соответствующую логику в пользовательский тип. Я часто обнаруживаю, что в зависимости от типа, который у вас есть «вложенные» типы коллекций, пользовательский тип более эффективно инкапсулирует , что означает внутренней коллекции.

6 голосов
/ 10 апреля 2011

Первый подход:

List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.Except(listToRemove).Count() == 0);

Это также удаляет список {2, 1}

Второй подход (предпочтительно):

List<int> listToRemove = new List<int> { 1, 2 };
list.RemoveAll(innerList => innerList.SequenceEqual(listToRemove));

При этом удаляются все списки, содержащие ту же последовательность, что и предоставленный список.

4 голосов
/ 10 апреля 2011

Список равенство является ссылочным равенством.Он не удалит список, если у него нет той же ссылки, что и у списка во внешнем списке.Вы можете создать новый тип, который реализует равенство как набор равенств, а не ссылочное равенство (или вас тоже заботит порядок)?Тогда вы можете составить списки этого типа.

2 голосов
/ 10 апреля 2011

Это просто не сработает, потому что вы пытаетесь удалить новый список (такой тип ключевого слова new), а не тот, который вы просто добавили туда.Например, следующий код создает два разных списка, поскольку они не являются одним и тем же списком , хотя они выглядят одинаковыми:

var list0 = new List<int> { 1, 2 };

var list1 = new List<int> { 1, 2 };

Тем не менее, следующее создает один единственный список, но две ссылки на тот же список :

var list0 = new List<int> { 1, 2 };

var list1 = list0;

Следовательно, вы должны сохранять ссылку на списки, которые вы помещаете втам вы должны захотеть воздействовать на них с Remove в будущем, так что:

var list0 = new List<int> { 1, 2 };

listOfLists.Remove(list0);
1 голос
/ 10 апреля 2011

Это разные объекты. Попробуйте это:

  List<int> MyList =  new List<int> { 1, 2 };   

  List<List<int>> list = new List<List<int>>();
  list.Add(new List<int> { 0, 1, 2 });
  list.Add(MyList);
  list.Add(new List<int> { 4 });
  list.Add(new List<int> { 0, 1, });

  list.Remove(MyList);
0 голосов
/ 10 апреля 2011

Вам необходимо указать ссылку на список, который вы хотите удалить:

list.Remove(list[1]);

что на самом деле совпадает с

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