Написание удаления имени цикла для списка - PullRequest
4 голосов
/ 04 марта 2010

Я пытаюсь создать эффективный метод удаления для работы со списком. Эта ситуация выглядит следующим образом:

Скажем, например, У меня есть (потенциально) огромный список имен:

Alex Smith
Anna Hobb
Bertie Blackman
Bill Clinton
David Smith
David Warner
George Jung
George Washington
William Wobbits

Допустим, что это List<Person> с Person, имеющим свойства FirstName и LastName. Как и в примере, есть возможность для двух людей, имеющих общее имя FirstName. Что мне нужно сделать, так это просмотреть список и удалить всех Давидов, например.

Я просматривал все Давиды, добавлял их в список DeletePerson, затем повторял цикл для каждого DeletePerson и удалял. Я уверен, что будет более эффективный метод? Эффективность не критична в этом приложении, но это просто кажется слишком сложным, и я думаю, что после буквы D в имени, которое мы знаем, мы больше не будем добавлять в список DeletePerson (при условии, что список отсортирован по алфавиту)

Спасибо!

Ответы [ 2 ]

6 голосов
/ 04 марта 2010

Обновленный ответ:

Если нам не разрешено использовать функции RemoveAll или LINQ, которые делают всю работу за нас, это способ сделать это более «вручную»:

    List<Person> newPersons = new List<Person>();
    foreach (Person person in persons)
    {
        if (person.FirstName != "David")
            newPersons.Add(person);
    }
    persons = newPersons();

Создание нового списка очень быстро в .NET. Удаление элементов по одному происходит медленно, потому что сначала каждый элемент для удаления должен быть найден в списке, а затем, когда он удаляется, остальная часть списка должна быть перемещена вверх, чтобы заполнить пробел. Это намного медленнее, чем метод, который я дал выше.

Чтобы сделать операцию удаления еще быстрее, список можно сохранить в отсортированном порядке или сгруппировать по имени. Но тогда первоначальное создание списка будет медленнее.


Старый ответ:

Кажется, вы заинтересованы в кратком решении, а не в оптимальном. Если вы используете .NET 3.5, вы можете использовать это:

persons = persons.Where(person => person.FirstName != "David").ToList();

Да, и у List есть метод RemoveAll:

names.RemoveAll(person => person.FirstName == "David");

(Примечание Джимми опубликовал идею RemoveAll до того, как я это сделал.)

3 голосов
/ 04 марта 2010

Для краткого подхода используйте RemoveAll.

list.RemoveAll(person => person.FirstName == "David")

Для эффективного (возможно, я не запускал тесты) подхода, основанного на порядке в списке, используйте List.RemoveRange - но вам придется найти индексы.

class NameComparer : IComparer<Name>
{
    public int Compare(Name x, Name y) { 
        return x.First.CompareTo(y.First); 
    }
}
...
...
var comparer = new NameComparer();
var david = new Name { First = "David" };
int guess = list.BinarySearch(david, comparer);
int start, end;
start = list.FindLastIndex(guess, person => person.First != "David") + 1;
if (start > 0 && list[start].First == "David") {
    end = list.FindIndex(guess, person => person.First != "David");
    list.RemoveRange(start, end - start);
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...