2016-11-14 1 views
2

У меня есть список, который может содержать или не содержать уникальный элемент, удовлетворяющий заданному предикату. Я ищу выражение, которое оценивает элемент, удовлетворяющий этому предикату, если он существует и является уникальным, и в противном случае возвращает None. Что-то вродеИдиома Python для возврата единственного элемента или None

numbers = [4, 3, 9, 7, 1, 2, 8] 
print(the(item for item in numbers if item > 10))  # None 
print(the(item for item in numbers if item % 2 == 0)) # None 
print(the(item for item in numbers if item % 7 == 0)) # 7 

Есть встроенный идиома для этого, или я должен написать свою собственную the функцию?

+0

Почему мой собственный ответ был удален с помощью консервированного «звукового сигнала», это не обоснованный ответ? – user3840170

ответ

0

Для записи, я могу просто написать the, как

def the(it): 
    it = iter(it) 
    try: 
     value = next(it) 
    except StopIteration: 
     return None 
    try: 
     next(it) 
    except StopIteration: 
     return value 
    return None 
0

Вы можете использовать следующий ленивый подход. Получить следующие два элемента из выражения генератора и возврата None если второй элемент из генератора не None:

def func(lst, pred): 
    gen = (i for i in lst if pred(i)) 
    v, w = next(gen, None), next(gen, None) 
    return v if w is None else None 


print(func([4, 3, 9, 7, 1, 2, 8], lambda x: x>10)) 
# None 
print(func([4, 3, 9, 7, 1, 2, 8], lambda x: x % 2 == 0)) 
# None 
print(func([4, 3, 9, 7, 1, 2, 8], lambda x: x % 7 == 0)) 
# 7 
print(func([4, 3, 9, 0, 1, 2, 8], lambda x: x % 7 == 0)) 
# 0 
+0

«_and_ is unique» – TigerhawkT3

+1

Использование набора позволит удалить дубликаты. Я предполагаю 'print ((item for item in (1,1,2,2), если item% 2 == 0))' должен быть 'None'. – TigerhawkT3

+0

@ TigerhawkT3 Не считал это. Обновлено –

4

Я не знаю ни одного способа выражения для этого, но это просто функция должна работать:

def the(it, cond): 
    l = [ i for i in it if cond(i) ] 
    return l[0] if len(l) == 1 else None 

Тест:

>>> print(the(numbers,(lambda x: x > 10))) 
None 
>>> print(the(numbers,(lambda x: x % 7 == 0))) 
7 
>>> print(the(numbers,(lambda x: x % 2 == 0))) 
None 
+1

Может быть единственным выражением с помощью '(l + [None]) [:: 2] [- 1]' или '((l + [None]) * 3) [2]', но я действительно не думаю, что они хорошие :-) –

0

Это должно быть простое решение этой проблемы:

def the(items): 
    return items[0] if (len(items) == 1) else None 

numbers = [4, 3, 9, 7, 1, 2, 8] 
print(the([item for item in numbers if item > 10]))  # None 
print(the([item for item in numbers if item % 2 == 0])) # None 
print(the([item for item in numbers if item % 7 == 0])) # 7 

Вы также можете применить следующий формат. Это может быть не проще с точки зрения кода, но это, конечно, быстрее, когда количество элементов велико.

print(the(list(filter(lambda x: x > 10, numbers))))  # None 
print(the(list(filter(lambda x: x % 2 == 0, numbers)))) # None 
print(the(list(filter(lambda x: x % 7 == 0, numbers)))) # 7 
1

Вы можете попробовать просить двух элементов с islice, было бы немного проще:

def the(it): 
    tmp = list(islice(it, 2)) 
    return tmp[0] if len(tmp) == 1 else None 

Или петля:

def the(it): 
    value = None 
    for i, value in enumerate(it): 
     if i == 1: 
      return None 
    return value 

Или еще один способ использования next:

def the(it): 
    first = next(it, None) 
    o = object() 
    if next(it, o) is o: 
     return first 

Или похожие на:

def the(it): 
    first = next(it, None) 
    try: 
     next(it) 
    except: 
     return first 
Смежные вопросы