Как обработать ошибку деления на ноль при хешировании значений в двух последовательностях - PullRequest
1 голос
/ 10 мая 2011

У меня есть два списка кортежей фиксированной длины. Эта функция вычисляет долю (отношение) для соответствующих элементов (примечание, 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]]  

Спасибо.

Ответы [ 4 ]

4 голосов
/ 10 мая 2011
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)
    ]
3 голосов
/ 10 мая 2011

Используйте троичный оператор a if x else b (эквивалентный выражению C / 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)]
0 голосов
/ 10 мая 2011

Ну, вы МОЖЕТЕ сделать хэш-функцию без проверки знаменателя.Хитрость заключается в том, чтобы гарантировать, что знаменатель никогда не равен 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.По крайней мере, это техника, и вам нужно выяснить, можете ли вы использовать ее для создания значимой хэш-функции для вашего ввода.Приведенный выше пример для техники может или не может быть полезным для вас (или кого-либо) в качестве хэш-функции.Является ли этот метод пригодным для создания хорошо читаемого кода, это также другая проблема.

0 голосов
/ 10 мая 2011

Если вы хотите сделать это в Python, нет никакого способа, кроме как выполнить тест каждого элемента. Обратите внимание, что это вовсе не увеличивает время асимптотики и довольно дешево. Это вовсе не "грубая сила".

Если вы действительно заботились о синтаксисе и совсем не заботились о скорости, вы можете заключить каждое число в свой собственный класс MyNumber со специальными правилами для деления. Это, конечно, приведет к совершенно ужасным накладным расходам.

Вы также можете обернуть свои вычисления в try...except, который возвращает float('nan') при исключении, но это эквивалентно выполнению "проверки каждого значения". Даже встроенная функция языка, который это сделал, эквивалентна выполнению «теста каждого значения» (это просто выполнение теста за вашей спиной).

...