Выражения этого типа часто встречаются в вопросах Python по SO. Либо для доступа ко всем элементам итерируемого
for i in range(len(a)):
print(a[i])
Это просто громоздкий способ написания:
for e in a:
print(e)
Или для присвоения элементам итерируемого:
for i in range(len(a)):
a[i] = a[i] * 2
Что должно быть таким же, как:
for i, e in enumerate(a):
a[i] = e * 2
# Or if it isn't too expensive to create a new iterable
a = [e * 2 for e in a]
Или для фильтрации по индексам:
for i in range(len(a)):
if i % 2 == 1: continue
print(a[i])
Что можно выразить так:
for e in a [::2]:
print(e)
Или когда вам просто нужна длина списка, а не его содержимое:
for _ in range(len(a)):
doSomethingUnrelatedToA()
Что могло быть:
for _ in a:
doSomethingUnrelatedToA()
В Python мы имеем enumerate
, нарезка, filter
, sorted
и т.д. ... Как питон for
конструкция предназначена перебрать итерируемые и не только в диапазон целых чисел, есть ли реальные потребительные случаи , когда вам нужны in range(len(a))
?
range(len(a))
обычно это люди, которые довольно неопытны в Python (хотя и не обязательно в программировании в целом).range(len(a))
тогда, когда изучал Python. В настоящее время я этого не делаю, потому что, как вы сказали, его довольно легко заменить.range(len(a))
часто, потому что мне нужно не содержимое списка a, а только его длина.for i in range(len(a)): doSomethingAbout(a[i+1] - a[i])
Как это обойти?Ответы:
Если вам нужно работать с индексами последовательности, тогда да - вы используете его ... например, для эквивалента numpy.argsort ...:
>>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0]
источник
[ix for ix, _ in sorted(enumerate(a), key=lambda i: i[1])]
хотя, возможно, ваш, возможно, лучше и интереснее.Что делать, если вам нужно получить доступ к двум элементам списка одновременно?
for i in range(len(a[0:-1])): something_new[i] = a[i] * a[i+1]
Вы можете использовать это, но, вероятно, это менее понятно:
for i, _ in enumerate(a[0:-1]): something_new[i] = a[i] * a[i+1]
Лично я тоже не на 100% доволен!
источник
for ix, i in enumerate(a)
кажется эквивалентным, нет?for a1,a2 in zip(a[:-1],a[1:])
Краткий ответ : с математической точки зрения - нет, с практической - да, например, для преднамеренного программирования.
Технически ответ был бы «нет, это не нужно», потому что это можно выразить с помощью других конструкций. Но на практике я использую
for i in range(len(a)
(илиfor _ in range(len(a))
если мне не нужен индекс), чтобы явно указать, что я хочу повторять столько раз, сколько есть элементов в последовательности, без необходимости использовать элементы в последовательности для чего-либо.Итак: "А есть ли необходимость?" ? - да, мне это нужно, чтобы выразить смысл / намерение кода для удобства чтения.
См. Также: https://en.wikipedia.org/wiki/Intentional_programming
И очевидно, что если нет коллекции, которая вообще связана с итерацией,
for ... in range(len(N))
это единственный вариант, чтобы не прибегать кi = 0; while i < N; i += 1 ...
источник
for _ in range(len(a))
передfor _ in a
?a
" вместо "для каждого элемент вa
, независимо от содержанияa
" ... так что это просто нюанс преднамеренного программирования.'hello'
с таким количеством элементов, как в спискеa
, используйтеb = ['hello'] * len(a)
Не Судя по комментариям, а также личного опыта, я говорю нет, нет необходимости в
range(len(a))
. Все, что вы можете сделать,range(len(a))
можно сделать другим (обычно гораздо более эффективным) способом.Вы привели много примеров в своем посте, поэтому я не буду их здесь повторять. Вместо этого я приведу пример для тех, кто говорит: «Что, если мне нужна только длина
a
, а не предметы?». Это один из немногих случаев, когда вы могли бы подумать об использованииrange(len(a))
. Однако даже это можно сделать так:>>> a = [1, 2, 3, 4] >>> for _ in a: ... print True ... True True True True >>>
Ответ Клементса (как показано Алликом) также можно переработать, чтобы удалить
range(len(a))
:>>> a = [6, 3, 1, 2, 5, 4] >>> sorted(range(len(a)), key=a.__getitem__) [2, 3, 1, 5, 4, 0] >>> # Note however that, in this case, range(len(a)) is more efficient. >>> [x for x, _ in sorted(enumerate(a), key=lambda i: i[1])] [2, 3, 1, 5, 4, 0] >>>
Итак, в заключение,
range(len(a))
не нужно . Его единственный положительный момент - читаемость (его цель ясна). Но это всего лишь предпочтения и стиль кода.источник
for _ in a:
как «Итерировать по a, но игнорировать его содержимое», но я интерпретируюfor _ in range(len(a))
как «Получить длину a, затем создать несколько целых чисел той же длины и, наконец, игнорировать содержимое».range(len(a))
сценария «Я должен использовать или я не могу этого сделать».Иногда Matplotlib требуется
range(len(y))
, например, в то время какy=array([1,2,5,6])
,plot(y)
работает отлично,scatter(y)
не делает. Надо писатьscatter(range(len(y)),y)
. (Лично я считаю, что это ошибка вscatter
;plot
и его друзьях,scatter
и поэтомуstem
следует как можно чаще использовать одни и те же последовательности вызовов.)источник
Приятно иметь, когда вам нужно использовать индекс для каких-то манипуляций, а наличия текущего элемента недостаточно. Возьмем, к примеру, двоичное дерево, которое хранится в массиве. Если у вас есть метод, который просит вас вернуть список кортежей, содержащий все прямые дочерние узлы, вам понадобится индекс.
#0 -> 1,2 : 1 -> 3,4 : 2 -> 5,6 : 3 -> 7,8 ... nodes = [0,1,2,3,4,5,6,7,8,9,10] children = [] for i in range(len(nodes)): leftNode = None rightNode = None if i*2 + 1 < len(nodes): leftNode = nodes[i*2 + 1] if i*2 + 2 < len(nodes): rightNode = nodes[i*2 + 2] children.append((leftNode,rightNode)) return children
Конечно, если элемент, над которым вы работаете, является объектом, вы можете просто вызвать метод get children. Но да, вам действительно нужен индекс, только если вы делаете какие-то манипуляции.
источник
У меня есть вариант использования, который я не верю ни в один из ваших примеров.
boxes = [b1, b2, b3] items = [i1, i2, i3, i4, i5] for j in range(len(boxes)): boxes[j].putitemin(items[j])
Я относительно новичок в python, хотя очень рад узнать более элегантный подход.
источник
[a - b for a, b in zip(list1, list2)]
он намного лучше, чем[list1[i] - list2[i] for i in range(len(list1))]
... Спасибо!Если вам нужно перебрать первые
len(a)
элементы объектаb
(который больше чемa
), вам, вероятно, следует использоватьrange(len(a))
:for i in range(len(a)): do_something_with(b[i])
источник
for b_elem in b[:len(a)]:...
itertools.islice
Вместо этого следует использовать .Иногда вас действительно не волнует сама коллекция . Например, создание простой линии соответствия модели для сравнения «приближения» с необработанными данными:
fib_raw = [1, 1, 2, 3, 5, 8, 13, 21] # Fibonacci numbers phi = (1 + sqrt(5)) / 2 phi2 = (1 - sqrt(5)) / 2 def fib_approx(n): return (phi**n - phi2**n) / sqrt(5) x = range(len(data)) y = [fib_approx(n) for n in x] # Now plot to compare fib_raw and y # Compare error, etc
В этом случае значения самой последовательности Фибоначчи не имели значения. Все, что нам здесь нужно, это размер входной последовательности, с которой мы сравниваем.
источник
Очень простой пример:
def loadById(self, id): if id in range(len(self.itemList)): self.load(self.itemList[id])
Я не могу придумать решение, в котором бы быстро не использовалась композиция range-len.
Но, вероятно, вместо этого это должно быть сделано,
try .. except
чтобы остаться питоническим, я думаю ...источник
if id < len(self.itemList)
Ноtry...except
лучше, как вы говорите.Мой код:
s=["9"]*int(input()) for I in range(len(s)): while not set(s[I])<=set('01'):s[i]=input(i) print(bin(sum([int(x,2)for x in s]))[2:])
Это двоичный сумматор, но я не думаю, что диапазон len или внутреннюю часть можно заменить, чтобы сделать его меньше / лучше.
источник