Синтаксический сахар для запроса списка Python, какой элемент появляется первым - PullRequest
12 голосов
/ 07 декабря 2011

У меня есть список многих элементов.

Я забочусь о двух его элементах, a и b.

Я не знаю порядок списка и не хочу его сортировать.

Есть ли хороший однострочный, который вернет True, если a произойдет до b и false в противном случае?

Ответы [ 4 ]

9 голосов
/ 07 декабря 2011

В интересах разнообразия вы также можете:

b in l[l.index(a):]

Это будет True, если a == b.Если вы знаете, что a != b,

b in l[l.index(a) + 1:]
8 голосов
/ 07 декабря 2011

Редактировать: переписано, чтобы проверить больше случаев

ОК, так что эта проблема требует немного больше работы. Марк Байерс абсолютно прав в том, что мой первый тест охватывал только те случаи, когда результат был бы True. Это особенно актуально, потому что нам нужны обработчики исключений для других решений. Итак, я углубился в детали:

stmts = {
"Mark Byers: ": "x = l.index(a) < l.index(b)",
"jcollado: ": """try:
    x = bool(l.index(b, l.index(a)))
except ValueError:
    x = False""",
"Greg Hewgill: ": """try:
   x = b in l[l.index(a):]
except ValueError:
   x = False"""
}

setups = ["a = 80; b = 90; l = list(range(100))", 
          "a = 5; b = 10; l = list(range(100))", 
          "a = 90; b = 80; l = list(range(100))",
          "a = 10; b = 5; l = list(range(100))"]

import timeit
for se in setups:
    print(se)
    for st in stmts:
        print(st, timeit.timeit(stmt=stmts[st], setup=se))
    print()

Результат:

a = 80; b = 90; l = list(range(100))
Mark Byers:  5.760545506106019
Greg Hewgill:  3.454101240451526     # Tie!
jcollado:  3.4574156981854536        # Tie!


a = 5; b = 10; l = list(range(100))
Mark Byers:  1.0853995762934794      # Close runner-up!
Greg Hewgill:  1.7265326426395209
jcollado:  1.0528704983320782        # Winner!

a = 90; b = 80; l = list(range(100))
Mark Byers:  5.741535600372806
Greg Hewgill:  3.623253643486848     # Winner!
jcollado:  4.567104188774817

a = 10; b = 5; l = list(range(100))
Mark Byers:  1.0592141197866987      # Winner!
Greg Hewgill:  4.73399648151641
jcollado:  4.77415749512712

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

7 голосов
/ 07 декабря 2011

Вы можете использовать list.index:

l.index(a) < l.index(b)

Это, конечно, предполагает, что оба элемента присутствуют в списке.

5 голосов
/ 07 декабря 2011

Ответ от Mark Byers работает отлично, но он не будет очень эффективным, если список длинный и оба элемента близки к концу.

Чтобы просмотреть список всего один раз, вы можете использовать это:

l.index(b, l.index(a))

Требуется однострочник, но в любом случае вам нужно будет захватить исключение ValueError.

...