2015-05-04 3 views
2

Я хотел бы вернуть элемент в списке, если выполнены определенные условия. Одним из условий является то, что мой проект "Project A", а другой - t[1] не None для всех подсписок, которые содержат "Project A". Код у меня есть, но он кажется неэффективным. Как я могу объединить это?Максимальное значение, если значения не равны - python

mylist = [(1, None, "Project A"), (2, 3, "Project A"), (3, 6, "Project B")] 

try: 
    if None not in [t[1] for t in mylist if t[2] == "Project A"]: 
     print max(t for t in mylist if t[2] == "Project A" and t[1] is not None) 
    else: 
     print "no match" 
except ValueError: 
    print "no match" 
+1

Если ваш код работает, отправить его на HTTP: //codereview.stackexchange.com/ для предложений об улучшениях. – ILostMySpoon

+5

@ILostMySpoon: вопрос совершенно по теме, и это всего лишь небольшой фрагмент. Это не подходит для КР. Можете ли вы просмотреть CR [справочную информацию по теме] (http://codereview.stackexchange.com/help/on-topic), прежде чем рекомендовать людям перепродавать там? –

+0

@MartijnPieters * ".. это всего лишь небольшой фрагмент. Это не подходит для CR, поэтому" * - насколько я могу сказать, вопрос по теме на обоих сайтах. Где вы читали об исключении «небольших фрагментов»? – jfs

ответ

1
tmp = [x for x in mylist if x[2] == "Project A"] 
if tmp and None not in zip(*tmp)[1]: 
    print max(tmp) 
else: 
    print "no match" 
+0

Не могли бы вы также объяснить свое решение купе предложений? – Magnilex

+0

@Magnilex Я думаю, что это довольно прямолинейно. Какая часть неясна? –

+1

Это не для меня, но ваш ответ попал в очередь просмотра для потенциально низкого качества вопроса, поэтому мой комментарий. Помните, что даже если это тривиально, небольшое объяснение делает ответ лучше. – Magnilex

1

Так как вам нужно проверить все соответствующие записи в любом случае, лучшим вариантом является использование прямой вверх for петлю; вспыхнуть, когда условие None не соблюдено:

found = None 
for entry in mylist: 
    if entry[2] == 'Project A': 
     if entry[1] is None: 
      print 'No match' 
      break 
     if not found or entry > found: 
      found = entry 
else: 
    # only executed when there was no break! 
    print found or 'No match' 

else ветвь for цикла выполняется только тогда, когда цикл for завершения итерации. Это произойдет только в том случае, если было найдено Project A записей, где t[1] был установлен в None.

Поскольку все еще существует вероятность того, что есть 0 записей, которые соответствуют названию проекта, found настроен на None; это None, когда вы достигнете else, блокируйте цикл, если никакие записи не должны совпадать.

Demo, перевернув нашел None случай в виде исключения, чтобы показать разницу:

>>> def find_max_project(projects, target): 
...  found = None 
...  for entry in projects: 
...   if entry[2] == target: 
...    if entry[1] is None: 
...     raise ValueError('no match') 
...    if not found or entry > found: 
...     found = entry 
...  else: 
...   return found 
... 

>>> find_max_project([(1, None, "Project A"), (2, 3, "Project A"), (3, 6, "Project B")], 'Project A') 
Traceback (most recent call last): 
    File "<stdin>", line 1, in <module> 
    File "<stdin>", line 7, in find_max_project 
ValueError: 'no match' 
>>> find_max_project([(1, 4, "Project A"), (2, 3, "Project A"), (3, 6, "Project B")], 'Project A') 
(2, 3, 'Project A') 
>>> find_max_project([(1, 2, "Project A"), (1, 3, "Project A")], 'Project A') 
(1, 3, 'Project A') 
>>> find_max_project([(1, 2, "Project B"), (1, 3, "Project B")], 'Project A') 
>>> find_max_project([(1, 2, "Project B"), (1, 3, "Project B")], 'Project A') is None 
True 

Обратите внимание, что в этой версии мы не даже действительно нужно поставить последнюю строку в else блоке больше , поскольку использование исключения завершает функцию теперь.

+0

Вы должны сломать, если это * *. Кроме того, печатает неправильный элемент для ввода '[(1, 2,« Проект А »), (1, 3,« Проект А »)]'. –

+0

@StefanPochmann: ах, действительно; моя логика перевернулась. Я также скорректировал, чтобы принимать во внимание * оба значения. –

+0

Вы также можете избавиться от max_value и просто сказать 'if not found or entry> found: found = entry' –

0

Я предпочитаю простую for петлю Martijn, но только для обсуждения вы могли бы использовать key параметр, чтобы значение None быть не более, если он существует, в противном случае возвращает максимум записей:

try: 
    result = max((t for t in mylist if t[2] == "Project A"), 
       key=lambda x: (x[1] is None, x)) 
    print 'no match' if result[1] == None else result 
except ValueError: 
    print 'no match' 

Если вам гарантировано, что в списке Project A, вы можете избавиться от блока try.

+0

Вы также можете использовать 'key = lambda x: (x [1] is None, x)'. –

+0

@achampion вы можете объяснить свое использование 'lamba'. Не очень хорошо знаком с этим. – user2242044

+0

Посмотрите параметр 'key' на' max', он принимает функцию, которая передается каждому элементу, и результат используется для сравнения. 'lambda' - это анонимная функция, которая принимает' x' и возвращает значение, используемое для сравнения. И мне очень нравится решение @ Stefan и обновилось. Это решение гарантирует, что если в списке есть «Нет», он возвращается как max, иначе возвращается максимум. – AChampion

1

Вы можете фильтровать и возвращать макс, если таковые имеются Нет это с "Project A" вы не должны возвращаться сразу же, что нет матча:

def filtered(l,proj): 
    filt = [] 
    for t in l: 
     if t[2] == proj: 
      if t[1] is None: 
       return "No match" 
      filt.append(t) 
    return max(filt)