Промежуточная переменная в понимании списка для одновременной фильтрации и преобразования

У меня есть список векторов (в Python), которые я хочу нормализовать, и в то же время удаляя векторы, которые изначально имели небольшие нормы.

Список входных данных, например,

a = [(1,1),(1,2),(2,2),(3,4)] 

И мне нужен вывод (x * n, y * n) с n = (x * 2 + y * 2) ** – 0.5

Если бы мне просто нужны были нормы, например, это было бы легко с пониманием списка:

 an = [ (x**2+y**2)**0.5 for x,y in a ] 

Было бы также легко хранить только нормализованное значение х, например, но я хочу, чтобы эта временная переменная «n» использовалась в двух вычислениях и выбрасывала ее.

Я не могу просто использовать функцию лямбда слишком, потому что мне также нужно n, чтобы отфильтровать список. Итак, каков наилучший способ?

Прямо сейчас я использую это вложенное понимание списка здесь (с выражением во внутреннем списке):

 a = [(1,1),(1,2),(2,2),(3,4)] [(x*n,y*n) for (n,x,y) in (( (x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 0.4] # Out[14]: # [(0.70710678118654757, 0.70710678118654757), # (0.60000000000000009, 0.80000000000000004)] 

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

3 Solutions collect form web for “Промежуточная переменная в понимании списка для одновременной фильтрации и преобразования”

 Is this really the best way? 

Ну, это работает эффективно, и если вы действительно хотите писать oneliners, тогда это лучшее, что вы можете сделать.

С другой стороны, простая 4-строчная функция будет делать то же самое яснее:

 def normfilter(vecs, min_norm): for x,y in vecs: n = (x**2.+y**2.)**-0.5 if min_norm < n: yield (x*n,y*n) normalized = list(normfilter(vectors, 0.4)) 

Btw, есть ошибка в вашем коде или описании – вы говорите, что вы отфильтровываете короткие векторы, но ваш код делает наоборот: p

Это говорит о том, что использование форлупа может быть самым быстрым способом. Обязательно проверьте результаты timeit на своем собственном компьютере, так как эти результаты могут варьироваться в зависимости от ряда факторов (аппаратное обеспечение, ОС, версия Python, длина a т. Д.).

 a = [(1,1),(1,2),(2,2),(3,4)] def two_lcs(a): an = [ ((x**2+y**2)**0.5, x,y) for x,y in a ] an = [ (x*n,y*n) for n,x,y in an if n < 0.4 ] return an def using_forloop(a): result=[] for x,y in a: n=(x**2+y**2)**0.5 if n<0.4: result.append((x*n,y*n)) return result def using_lc(a): return [(x*n,y*n) for (n,x,y) in (( (x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 0.4] 

дает следующие результаты:

 % python -mtimeit -s'import test' 'test.using_forloop(test.a)' 100000 loops, best of 3: 3.29 usec per loop % python -mtimeit -s'import test' 'test.two_lcs(test.a)' 100000 loops, best of 3: 4.52 usec per loop % python -mtimeit -s'import test' 'test.using_lc(test.a)' 100000 loops, best of 3: 6.97 usec per loop 

Кража кода из unutbu, вот более крупный тест, включая версию numpy и версию итератора. Обратите внимание, что преобразование списка в numpy может стоить некоторое время.

 import numpy # a = [(1,1),(1,2),(2,2),(3,4)] a=[] for k in range(1,10): for j in range(1,10): a.append( (float(k),float(j)) ) npa = numpy.array(a) def two_lcs(a): an = [ ((x**2+y**2)**-0.5, x,y) for x,y in a ] an = [ (x*n,y*n) for n,x,y in an if n < 5.0 ] return an def using_iterator(a): def normfilter(vecs, min_norm): for x,y in vecs: n = (x**2.+y**2.)**-0.5 if n < min_norm: yield (x*n,y*n) return list(normfilter(a, 5.0)) def using_forloop(a): result=[] for x,y in a: n=(x**2+y**2)**-0.5 if n<5.0: result.append((x*n,y*n)) return result def using_lc(a): return [(x*n,y*n) for (n,x,y) in (( (x**2.+y**2.)**-0.5 ,x,y) for x,y in a) if n < 5.0] def using_numpy(npa): n = (npa[:,0]**2+npa[:,1]**2)**-0.5 where = n<5.0 npa = npa[where] n = n[where] npa[:,0]=npa[:,0]*n npa[:,1]=npa[:,1]*n return( npa ) 

и результат …

 nlw@pathfinder:~$ python -mtimeit -s'import test' 'test.two_lcs(test.a)' 10000 loops, best of 3: 65.8 usec per loop nlw@pathfinder:~$ python -mtimeit -s'import test' 'test.using_lc(test.a)' 10000 loops, best of 3: 65.6 usec per loop nlw@pathfinder:~$ python -mtimeit -s'import test' 'test.using_forloop(test.a)' 10000 loops, best of 3: 64.1 usec per loop nlw@pathfinder:~$ python -mtimeit -s'import test' 'test.using_iterator(test.a)' 10000 loops, best of 3: 59.6 usec per loop nlw@pathfinder:~$ python -mtimeit -s'import test' 'test.using_numpy(test.npa)' 10000 loops, best of 3: 48.7 usec per loop 
  • суммировать список чисел в Python
  • Невозможно изменить элементы списка в цикле Python
  • Как должен быть извлечен определенный процент равномерно распределенных элементов списка Python?
  • Как заменить номера с порядком в списке (python)
  • сортировка кусочков пифа и списков
  • Получение последнего элемента списка в Python
  • Тип Python long vs C 'long long'
  • Заполнение вложенного словаря
  • Выбор случайных списков в python
  • Рекурсия обучения, сообщение об ошибке (аргумент не по умолчанию следует за аргументом по умолчанию) python
  • Сортировка словаря в список
  • Python - лучший язык программирования в мире.