У меня есть два списка кортежей с фиксированной длиной. Эта функция вычисляет долю (отношение) для соответствующих элементов (обратите внимание, fX()
не использует понимание для читаемости здесь).
>>> def fX(a,b):
>>> c=[]
>>> for i in range(len(a)):
>>> c.append([a[i][x]/float(a[i][x]+b[i][x]) for x in range(len(a[i]))])
>>> return c
Когда все значения отличны от нуля, fX()
работает:
>>> a[0]=(3, 4, 17, 9.6667, 6.6583, 0.4310, 1)
>>> b[0]=(4, 4, 12, 8.0, 3.2660, 0.0002, 1)
>>> fX(a,b)
>>> [[0.4286, 0.5, 0.5862, 0.5472, 0.6710, 0.9995, 0.5]]
Однако, когда любые значения пары суммируются с нулями, fX()
не выполняется:
>>> a[0]=(3, 4, 17, 9.6667, 6.6583, 0.4310, 0)
>>> b[0]=(4, 4, 12, 8.0, 3.2660, 0.0002, 0)
>>> fX(a,b)
Traceback (most recent call last):
File "<pyshell#59>", line 1, in <module>
fX(a,b)
File "<pyshell#52>", line 4, in fX
c.append([a[i][x]/float(a[i][x]+b[i][x]) for x in range(len(a[i]))])
ZeroDivisionError: float division
Мне нужна функция fY()
, которая дает этот желаемый результат, не прибегая к проверке грубой силы каждого значения:
>>> a[i]=(3, 4, 17, 9.6667, 6.6583, 0.4310, 0)
>>> b[i]=(4, 4, 12, 8.0, 3.2660, 0.0002, 0)
>>> fY()
>>> [[0.4286, 0.5, 0.5862, 0.5472, 0.6710, 0.9995, 0.0]]
Спасибо.
Используйте тернарный оператор a if x else b
(эквивалентный выражению C/С++/Java x ? a : b
), чтобы установить условие внутри понимания списка. Это дает эффективную реализацию Pythonic:
def fY(a, b):
return [[aij/float(aij + bij) if aij+bij != 0 else 0 for aij, bij in zip(ai, bi)]
for ai, bi in zip(a, b)]
def f_cell(a, b):
try: return a / float(a + b) # EAFP
except: return 0.0 # Or whatever other value you want for this case.
def fY(a,b):
return [
[f_cell(a_cell, b_cell) for a_cell, b_cell in zip(a_row, b_row)]
for a_row, b_row in zip(a, b)
]
Если вы хотите сделать это в python, нет никакого способа помимо теста каждого элемента. Обратите внимание, что это не увеличивает ваше асимптотическое время работы и довольно дешево. Это не "грубая сила" вообще.
Если вам действительно понравился синтаксис, и он не заботился о скорости, вы можете обернуть каждое число в свой собственный класс MyNumber
со специальными правилами для деления. Это, конечно же, приведет к совершенно ужасным накладным расходам.
Вы можете также обернуть вычисление в try...except
, который возвращает float('nan')
в качестве исключения, но это эквивалентно выполнению "теста каждого значения". Даже встроенная функция языка, которая сделала это, эквивалентна выполнению "теста каждого значения" (он просто выполняет тест за спиной).
Ну, вы можете сделать хэш-функцию без проверки знаменателя. Хитрость заключается в том, чтобы гарантировать, что знаменатель никогда не равен 0. Вы можете сделать это побитовым или-во что-то в знаменателе, убедившись, что хотя бы один незнаковый бит установлен до деления.
Здесь пример fY:
def fY(a,b):
c=[]
for i in range(len(a)):
# Or in a bit to make sure non zero
c.append([float(a[i][x])/(1 | int(a[i][x]+b[i][x])) for x in range(len(a[i]))])
return c
Обратите внимание, что знаменатель должен быть превращен в int. Это, по крайней мере, техническая возможность, чтобы выяснить, можете ли вы использовать ее для создания значимой хэш-функции для вашего ввода. Приведенный выше пример техники может или не может быть полезен вам (или кому-либо) как хеш-функции. Независимо от того, является ли это методом, который поддается созданию хорошего читаемого кода, также является еще одной проблемой.
[x] for x in range(len(...
- это форма повреждения мозга, вызванного такими языками, как C ++. Если вы хотите что-то сделать со всеми элементами списка, сделайте это с элементами списка , а не с элементами временного списка индексов той же длины, которую вы создаете после измерения оригинала. Итеративное добавление к пустому списку также является плохим стилем; вы уже знаете, как использовать понимание списка, поэтому примените ту же технику к внешнему петля.