Удаление альтернативных элементов в списке <T>
Каков наиболее эффективный способ удаления альтернативных (нечетных индексированных или даже индексированных) элементов в List<T>
без использования переменной списка владельцев места?
Также было бы полезно, если бы вы могли указать стоимость с каждым вашим ответом.
Я ищу способ эффективный, чтобы сделать это
Заранее спасибо
Ответы
Ответ 1
Если вы вызываете RemoveAt для каждого объекта, который вы удаляете, вы будете перемещать много данных. Наиболее эффективным является перемещение элементов вместе, которые вы хотите сохранить, а затем удалить неиспользуемые элементы в конце:
int pos = 0;
for (int i = 0; i < values.Count; i += 2, pos++) {
values[pos] = values[i];
}
values.RemoveRange(pos, values.Count - pos);
Edit:
Этот метод обработает список из миллиона ints за 15 мс. Используя RemoveAt, это займет три минуты...
Edit2:
Фактически вы можете начать с pos = 1 и я = 2 (или 3), так как первый элемент не нужно копировать самому себе. Это делает код немного менее очевидным, хотя.
Ответ 2
Только для рассмотрения решения, которое создает новый список, со старым списком вы можете сделать это:
var newList = old.Where((_, i) => i%2 != 0).ToList();
или, очевидно,
var newList = l.Where((_, i) => i%2 == 0).ToList();
в зависимости от выбранного вами варианта.
ИЗМЕНИТЬ
Ответ довольно быстрый. Если вы читаете что-то еще здесь, это потому, что я измерял на выходных и в выходные дни мозг смешно.:(
Решение о закрытии примерно на 40% быстрее, чем ответ. На 2 порядка быстрее. Я полагаю, что это будет действительно зависеть от того, насколько велик ваш список!
Ответ 3
И еще один вариант, похожий на Фрэнка, но с использованием закрытий. И это быстрее, чем версия Фрэнка.
bool isEven = true;
var newList = list.Where(x => isEven = !isEven).ToList();
Ответ 4
Я не уверен, что вы подразумеваете под альтернативным, но если вы имеете в виду "каждый другой элемент", следующий код будет работать. Он начнется с удаления 2-го элемента, затем 4-го и т.д.
List<T> list = GetTheList();
int i = 1;
while ( i < list.Count ) {
list.RemoveAt(i);
i++;
}
Ответ 5
Путь к Нирване вымощен отсроченным исполнением. Или что-то.
public static IEnumerable<T> AlternateItems<T>(this IEnumerable<T> source)
{
while (source.Any())
{
yield return source.First();
source = source.Skip(1);
if (source.Any()) source = source.Skip(1);
}
}
Это работает для всех последовательностей, а не только IList<>
. Стоимость итерации откладывается до итерации, что может быть большой победой, если в конце вам не нужно касаться всех элементов в списке.
В моих простых тестах производительность, когда вы перебираете весь список, не очень хороша, поэтому не забудьте проанализировать свою реальную ситуацию.
Ответ 6
for (int i=myList.length-1; i >= 0; i--)
if (i % 2 == 0)
myList.Remove(myList[i]);
Ответ 7
Очевидно, что это зависит от использования, но вы можете иметь обертку IList, которая умножает индекс, который вы даете ему на 2, и сообщает, что длина списка равна 1/2 (подробности указаны). Это O (1).
Ответ 8
Я бы использовал стандартный шаблон, обычно используемый для контейнеров STL.
Сделайте удаление, за которым следует удаление.
Таким образом, вы не будете путать людей, которые привыкли видеть этот шаблон.
template<typename T>
struct RemoveEven
{
RemoveEven():count(0) {}
bool operator()(T const&)
{
bool result = count%2 == 0;
count++;
return result;
}
private:
std::size_t count;
};
int main()
{
std::list<int> a;
a.erase(std::remove_if(a.begin(),a.end(),RemoveEven<int>()),a.end());
}