Как очистить list c
Перейти к содержимому

Как очистить list c

  • автор:

Очистка std::list с удалением объектов

Суть в том, что я циклически создаю объекты и помещаю их в list. Но как мне потом средствами самого list удалить все объекты из памяти? Или прийдётся ето делать вручную?

Вывод программы такой:

MyClass::MyClass(1) MyClass::MyClass(2) MyClass::MyClass(3) MyClass::MyClass(4) 

деструкторы класса не срабатывают. Может, я не правильно понимаю документацию, но здесь http://www.cplusplus.com/reference/list/list/clear/ написано:

All the elements in the list container are dropped: their destructors are called, and then they are removed from the list container, leaving it with a size of 0. 

почему тогда в моём случае деструкторы не вызываются?

Удалить все нулевые элементы из списка в C#

В этом посте будет обсуждаться, как удалить все пустые элементы из списка в C#.

1. Использование List.RemoveAll() метод

List’s RemoveAll() метод на месте удаляет все элементы из списка, соответствующие заданному условию. Его можно использовать следующим образом для удаления нулевых элементов из списка строк.

using System ;
using System . Collections . Generic ;
public class Example
public static void Main ( )
List < string >strings = new List < string >( ) < "A" , "B" , null , "C" , null >;
strings . RemoveAll ( s = > s == null ) ;
Console . WriteLine ( String . Join ( «, » , strings ) ) ; // A, B, C

The List.RemoveAll() метод принимает Predicate делегат, задающий условия удаления элементов. Чтобы удалить нулевые, пустые и пробельные символы из списка, вы можете использовать предопределенный делегат IsNullOrWhiteSpace . В качестве альтернативы вы можете использовать IsNullOrEmpty для удаления нулевых и пустых строк из списка.

Как очистить list c

Приветствую,
возникла проблема с удаление елемента списка.

 list int> c1; list int>::iterator c1_Iter; for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ ) < //что-то делаем с c1_Iter и поняли что нужно удалить этот элемент, но чтобы цикл продолжился >

c1.erase(c1_Iter); всё рушит и я почти понял почему

Подскажите как правильно удалить, пока приходит на ум только создать второй список на удаление и после цикла for все удалить.

Re: erase в std:list

От: Bell
Дата: 03.05.06 15:16
Оценка: 1 (1)

Здравствуйте, RSNT, Вы писали:

RSN>Приветствую,
RSN>возникла проблема с удаление елемента списка.

RSN> list int> c1; RSN> list int>::iterator c1_Iter; RSN>for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ ) RSN>< RSN>//что-то делаем с c1_Iter и поняли что нужно удалить этот элемент, но чтобы цикл продолжился RSN>> RSN>

RSN>c1.erase(c1_Iter); всё рушит и я почти понял почему

RSN>Подскажите как правильно удалить, пока приходит на ум только создать второй список на удаление и после цикла for все удалить.

list int> c1; list int>::iterator c1_Iter = c1.begin(), e = c1.end(); while(c1_Iter != e) < if(/*нужно удалить*/) c1_Iter = c1.erase(c1_Iter); else ++c1_Iter; >

Или же использовать метод списка remove_if.

Любите книгу — источник знаний (с) М.Горький
Re[2]: erase в std:list

От: denisku
Дата: 04.05.06 10:48
Оценка:

Здравствуйте, Bell, Вы писали:

B>

B>list int> c1; B> list int>::iterator c1_Iter = c1.begin(), e = c1.end(); B>while(c1_Iter != e) B> < B>if(/*нужно удалить*/) B> c1_Iter = c1.erase(c1_Iter); B> else B> ++c1_Iter; B>> B>

а вызов erase() не сделает e невалидным? имхо, надо бы сделать
while(c1_Iter != c1.end())
Извините за потраченный траффик..
Re[3]: erase в std:list

От: FreshMeat http://www.rsdn.org
Дата: 04.05.06 10:57
Оценка:

Здравствуйте, denisku, Вы писали:

D>а вызов erase() не сделает e невалидным?
Нет. Добавление/удаление элементов списка не влияет на валидность итераторов (видимо, с вектором спутал)
http://gzip.rsdn.ru/article/cpp/stl.xml#EMVBG

Автор(ы): Александр Степанов, Менг Ли

Список (List)
.
erase делает недействительными только итераторы и ссылки для стёртых элементов. Стирание единственного элемента — операция постоянного времени с единственным вызовом деструктора T. Стирание диапазона в списке занимает линейное время от размера диапазона, а число вызовов деструктора типа T точно равно размеру диапазона.

Хорошо там, где мы есть! 🙂
Re[4]: erase в std:list

От: saddva
Дата: 04.05.06 12:54
Оценка:

Здравствуйте, FreshMeat, Вы писали:

FM>Здравствуйте, denisku, Вы писали:

D>>а вызов erase() не сделает e невалидным?
FM>Нет. Добавление/удаление элементов списка не влияет на валидность итераторов (видимо, с вектором спутал)
FM>http://gzip.rsdn.ru/article/cpp/stl.xml#EMVBG

Автор(ы): Александр Степанов, Менг Ли

FM>Список (List)
FM>.
FM>erase делает недействительными только итераторы и ссылки для стёртых элементов. Стирание единственного элемента — операция постоянного времени с единственным вызовом деструктора T. Стирание диапазона в списке занимает линейное время от размера диапазона, а число вызовов деструктора типа T точно равно размеру диапазона.

А если удаляется последний элемент списка? Даже в этом случае e останется валидным?
Re[5]: erase в std:list

От: FreshMeat http://www.rsdn.org
Дата: 04.05.06 13:06
Оценка:

Здравствуйте, saddva, Вы писали:

S>А если удаляется последний элемент списка? Даже в этом случае e останется валидным?
Да. end() у списка сделан вообще достаточно хитро. Сырцы реализаций STL не копал, но есть сильное подозрение (следующее из логики работы класса), что end() фиксируется в момент создания списка и не изменяется все время жизни листа.

Хорошо там, где мы есть! 🙂
Re: erase в std:list

От: rg45
Дата: 05.05.06 14:00
Оценка:
> list int> c1; > list int>::iterator c1_Iter; > > for ( c1_Iter = c1.begin( ); c1_Iter != c1.end( ); c1_Iter++ ) > < >//что-то делаем с c1_Iter и поняли что нужно удалить этот элемент, но чтобы цикл продолжился > > > >

>
> c1.erase(c1_Iter); всё рушит и я почти понял почему
>
> Подскажите как правильно удалить, пока приходит на ум только создать второй список на удаление и после цикла for все удалить.

При помощи вспомогательного итератора проблема решается достаточно просто:

list int> c1; list int>::iterator c1_Iter, c1_Iter2; for ( c1_Iter = c1_Iter2 = c1.begin( ); c1_Iter != c1.end( ); c1_Iter = c1_Iter2) < ++c1_Iter2; //что-то делаем с c1_Iter. c1.erase(c1_Iter); >

как удалить из списка все единицы с#

У меня есть лист например [0, 1, 1, 1, 1] . Я хочу удалить отсюда все единицы, как это можно сделать?

List fishes = new List(5); fishes.Add(0); fishes.Add(1); fishes.Add(1); fishes.Add(1); fishes.Add(1); for (int i = 0; i < fishes.Count; i++) < if (fishes[i] == 1) < fishes.Remove(1); >> 

Такой цикл не подойдет ибо в какой-то момент i станет больше чем fishes.Count и при этом ещё не все единицы удалятся Можно создать новый лист и в него записывать все элементы, не равные единице, но не хочется создавать новый лист. Думаю какое условие можно придумать, чтобы реализовать мою задачу с помощью цикла

Отслеживать
47.6k 5 5 золотых знаков 22 22 серебряных знака 57 57 бронзовых знаков
задан 2 фев 2021 в 5:03
101 6 6 бронзовых знаков
добавьте внутрь if i—
2 фев 2021 в 5:32

2 ответа 2

Сортировка: Сброс на вариант по умолчанию

Можно оставить в списке только те элементы, которые не равны 1 используя LINQ:

fishes = fishes.Where(x => x != 1).ToList(); 

либо указать условие для удаления всех элементов:

fishes.RemoveAll(x => x == 1); 

Если надо именно в цикле, то при удалении элемента, надо понизить i .

for (int i = 0; i < fishes.Count; i++) < if (fishes[i] == 1) < fishes.RemoveAt(i); i--; >> 

Отслеживать
47.6k 5 5 золотых знаков 22 22 серебряных знака 57 57 бронзовых знаков
ответ дан 2 фев 2021 в 5:10
Архипов Владимир Архипов Владимир
490 2 2 серебряных знака 8 8 бронзовых знаков
к сожалению linq ещё не проходил
2 фев 2021 в 5:13
дополнил ответ без LINQ
2 фев 2021 в 5:24
c i— действительно работает, не знаю как до этого можно было додуматься, но спасибо
2 фев 2021 в 5:36
Можно еще лёгкий изврат int i; while ((i = fishes.IndexOf(1)) >= 0) fishes.RemoveAt(i); .
2 фев 2021 в 17:12

В ответе сверху три хороших варианта, а я приведу ещё два.

При удалении элемента сдвигаются все индексы, начиная с индекса следующего за удалённым элемента и до конца. Поэтому чтобы с индексами не было проблем, перебираем массив с конца:

for (int i = fishes.Count - 1; i >= 0; i--)

Каждое удаление элемента из середины — затратная операция, потому что нужно нужно сдвигать все элементы, возможно, по нескольку раз, в результате у кода квадратичная сложность. Поэтому сделаем такой трюк: пройдёмся по списку с начала в конец, и будем «уплотнять» его: перезаписывать элементы на освобождающиеся места, как на картинке

визуализация

Если идти слева направо, мы не будем при этом затирать нужные нам элементы.

За индекс сверху у нас будет отвечать переменная i , а за индекс снизу — j . В конце нужно будет «отрезать» ненужный хвост. Получается вот что:

int j = 0; for (int i = 0; i < fishes.Count; i++) < if (fishes[i] != 1) < if (i != j) // копировать в себя нет смысла fishes[j] = fishes[i]; j++; // продвигаем целевой индекс только если не единица >> fishes.RemoveRange(j, fishes.Count - j); 

Код здесь длиннее, но эффективнее на больших списках.

Проверка i != j , возможно, не очень хорошо влияет на предсказатель переходов процессора, поэтому не исключено, что без неё будет быстрее. Не тестировал.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *