LINUX.ORG.RU

python


0

0

Есть список. Нужно удалить из него какой-то элемент.

Можно сделать просто:

  for i in xrange (len (l)):
    if bad (l[i]):
      delete l[i]

Но мне не нравится, то что доступ по индексу, ведь для списка это не очень хорошо. Хотелось бы что-то вроде:

  for i in l:
    if bad (i):
      delete i   # но i всего лишь ссылка, то есть остается еще одна и элемент не будет удален

Как это сделать?

P.S. будел ли нормальным решением (по скорости в том числе):

  l = filter (lambda x: not bad (x), l)
или
  l = [x for x in l if not bad (x)]

Спасибо
anonymous
Ответ на: комментарий от yuriy123

lingvo заюзал, но только английский :)

А потом кстати вспомнил... у theatre of tragedy такая песня была - "Warum?"

anonymous
()

вроде обещали в путоне лямбду убрать. правда или нет?

Zert
()

>Но мне не нравится, то что доступ по индексу

У него списки "ненастоящие", доступ быстрый.

DonkeyHot ★★★★★
()

хм... могу ошибаться, но кажется есть pop... типа a.pop(2) удклит второй элемент

Не то?

php-coder ★★★★★
()

python: удаление элемента

> Есть список. Нужно удалить из него какой-то элемент.

> Можно сделать просто:

>  for i in xrange (len (l)):
>    if bad (l[i]):
>      delete l[i]

Действует только в случае удаления одного элемента. Т.е. корректно будет так:

  for i in xrange (len (l)):
    if bad (l[i]):
      delete l[i]
      break

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

>  for i in l:
>    if bad (i):
>      delete i   # но i всего лишь ссылка, то есть остается еще одна и элемент не будет удален

Это было бы совсем плохо, так как изменялся бы список, по которому идёт цикл.
Последствия непредсказуемы.

> P.S. будел ли нормальным решением (по скорости в том числе):

>  l = filter (lambda x: not bad (x), l)
> или
>  l = [x for x in l if not bad (x)]

IMHO, это самое нормальное решение, этот код легко написать и легко потом
понять, что он делает. Какой из двух -- дело вкуса. Для решения с filter
желательно, если есть возможность, создать вместо bad функцию good, возвращающую
противоположное значение, что позволит избавиться от not и от lambda.

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

DKorolkov
()
Ответ на: python: удаление элемента от DKorolkov

> При удалении нескольких элементов нужно учитывать, что с каждым удалённым элементом индексы последующих уменьшаются на 1, поэтому код будет сложнее.

Минимально: xrange( len(l) ) => xrange( len(l)-1, -1, -1 )

>> l = [x for x in l if not bad (x)]

> IMHO, это самое нормальное решение, этот код легко написать и легко потом понять, что он делает. Какой из двух -- дело вкуса.

Этот вариант делает копию списка. Со всеми вытекающими.

watashiwa_daredeska ★★★★
()
Ответ на: комментарий от watashiwa_daredeska

удаление элемента: копия vs цикл

>> При удалении нескольких элементов нужно учитывать, что с каждым удалённым элементом индексы последующих уменьшаются на 1, поэтому код будет сложнее.

> Минимально: xrange( len(l) ) => xrange( len(l)-1, -1, -1 )

Согласен, усложнение небольшое.

>>> l = [x for x in l if not bad (x)]

>Этот вариант делает копию списка. Со всеми вытекающими.

А что именно из этого вытекает?
Python, хотя и императивный язык, поощряет функциональный стиль, в том
числе создание копии вместо изменения "на месте". Думаю, вы не станете
спорить с тем, что вариант с созданием копии (с filter или списковым
включением) является более простым, компактным и понятным, чем вариант
с циклом?

А что касается эффективности, вот результат измерения скорости (для 
экономии памяти в некоторых случаях поможет itertools):
============================ Код ==============================
import profile
from itertools import ifilter, ifilterfalse

def good(x):
	return not (x % 2)

def bad(x):
	return x % 2

COUNT = 10000

def rem_for():
	for count in xrange(COUNT):
		l = range(10)
		for i in xrange(len(l)-1, -1, -1):
			if bad(l[i]):
				del(l[i])
	print l

def rem_filter():
	for count in xrange(COUNT):
		l = range(10)
		l = filter(good, l)
	print l

def rem_clist():
	for count in xrange(COUNT):
		l = range(10)
		l = [x for x in l if good(x)]
	print l

def rem_ifilter():
	for count in xrange(COUNT):
		l = range(10)
		for x in ifilter(good, l):
			pass
	print list(ifilter(good, l))

def rem_ifilterfalse():
	for count in xrange(COUNT):
		l = range(10)
		for x in ifilterfalse(bad, l):
			pass
	print list(ifilterfalse(bad, l))

profile.run('rem_for()')
profile.run('rem_filter()')
profile.run('rem_clist()')
profile.run('rem_ifilter()')
profile.run('rem_ifilterfalse()')
========================= Результат ===========================
[0, 2, 4, 6, 8]
         100003 function calls in 1.794 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.767    1.767 <string>:1(?)
        1    1.108    1.108    1.767    1.767 list_rem.py:12(rem_for)
   100000    0.659    0.000    0.659    0.000 list_rem.py:7(bad)
        0    0.000             0.000          profile:0(profiler)
        1    0.027    0.027    1.794    1.794 profile:0(rem_for())


[0, 2, 4, 6, 8]
         100003 function calls in 1.550 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.550    1.550 <string>:1(?)
        1    0.883    0.883    1.550    1.550 list_rem.py:20(rem_filter)
   100000    0.667    0.000    0.667    0.000 list_rem.py:4(good)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    1.550    1.550 profile:0(rem_filter())


[0, 2, 4, 6, 8]
         100003 function calls in 1.618 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.617    1.617 <string>:1(?)
        1    0.951    0.951    1.617    1.617 list_rem.py:26(rem_clist)
   100000    0.667    0.000    0.667    0.000 list_rem.py:4(good)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    1.618    1.618 profile:0(rem_clist())


[0, 2, 4, 6, 8]
         100013 function calls in 1.553 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.552    1.552 <string>:1(?)
        1    0.885    0.885    1.552    1.552 list_rem.py:32(rem_ifilter)
   100010    0.668    0.000    0.668    0.000 list_rem.py:4(good)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    1.553    1.553 profile:0(rem_ifilter())


[0, 2, 4, 6, 8]
         100013 function calls in 1.540 CPU seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
        1    0.000    0.000    1.540    1.540 <string>:1(?)
        1    0.895    0.895    1.540    1.540 list_rem.py:39(rem_ifilterfalse)
   100010    0.645    0.000    0.645    0.000 list_rem.py:7(bad)
        0    0.000             0.000          profile:0(profiler)
        1    0.000    0.000    1.540    1.540 profile:0(rem_ifilterfalse())

DKorolkov
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.