2009-09-28 3 views
5

Howdy, codeboys и codegirls!Оценка в двух списках:

Я столкнулся с простой проблемой, казалось бы, простым решением. Но, будучи неофитом Питона, я чувствую, что где-то есть лучший подход.

Скажем, у вас есть список смешанных строк. В мешке есть два основных типа струн: в них - «=» (a = картофель) и без них (Леди Джейн). Вам нужно отсортировать их по двум спискам.

Очевидный подход заключается в следующем:

for arg in arguments: 
    if '=' in arg: 
     equal.append(arg) 
    else: 
     plain.append(arg) 

Есть ли другой, более элегантный способ в него? Что-то вроде:

equal = [arg for arg in arguments if '=' in arg] 

, но для сортировки по нескольким спискам?

А что, если у вас есть несколько типов данных?

+3

Я думаю, что ваш очевидный подход совершенно хорош и гораздо читабельнее многих ответов предлагается до сих пор! –

+0

Действительно, я нахожу, что перечни понятий - одна из самых элегантных функций питона, которую я постоянно жажду при написании C++! 2 из них намного приятнее, чем любой из ответов. – Steg

ответ

4

Попробуйте

for arg in arguments: 
    lst = equal if '=' in arg else plain 
    lst.append(arg) 

или (свят некрасиво)

for arg in arguments: 
    (equal if '=' in arg else plain).append(arg) 

Третий вариант: Создать класс, который предлагает append() и рассортировывающую в несколько списков.

+0

Я нахожу более читаемым форму 'list = ('=' в arg) и равную или равную. – giorgian

+0

вы затеняете встроенный – SilentGhost

+0

Я думаю, что «a if cond else b» очень читаем английский; Я просто не люблю слишком много вкладывать в одну строку. –

4

Вы можете использовать itertools.groupby() для этого:

import itertools 
f = lambda x: '=' in x 
groups = itertools.groupby(sorted(data, key=f), key=f) 
for k, g in groups: 
    print k, list(g) 
+3

Я думал, что он попросил элегантного – Steg

+0

Сортировка делает его nlog (n), в то время как существует более простое решение O (n). –

1

Другой подход заключается в использовании функции filter, хотя это не является наиболее эффективным решением.
Пример:

>>> l = ['a=s','aa','bb','=', 'a+b'] 
>>> l2 = filter(lambda s: '=' in s, l) 
>>> l3 = filter(lambda s: '+' in s, l) 
>>> l2 
['a=s', '='] 
>>> l3 
['a+b'] 
2
def which_list(s): 
    if "=" in s: 
     return 1 
    return 0 

lists = [[], []] 

for arg in arguments: 
    lists[which_list(arg)].append(arg) 

plain, equal = lists 

Если у вас есть несколько типов данных, если добавить статью в which_list и инициализировать lists более пустые списки.

+0

, который может быть намного проще - см. Мой ответ. В противном случае наши ответы довольно близки. – PaulMcG

+0

Действительно, это может быть, но ОП спросил о случае более двух возможностей, с которыми я хотел иметь дело в первоначальном дизайне. –

+0

В этом случае, я думаю, словарь списков будет более ясным. Индексы списка не имеют смысла. –

3

Я бы просто пошел на два списка понятий. Хотя это накладывает некоторые накладные расходы (две петли в списке), более Pythonic использует понимание списка, чем использовать for. Это также (на мой взгляд) гораздо читабельнее, чем использование всяких действительно классных трюков, но об этом мало знают люди.

1

Я положил это вместе, а затем увидел, что Нед Батчелдер уже был на этом же пути. Однако я решил упаковать метод расщепления вместо выбора списка, и просто использовать неявные значения 0/1 для False и True.

def split_on_condition(source, condition): 
    ret = [],[] 
    for s in source: 
     ret[condition(s)].append(s) 
    return ret 

src = "z=1;q=2;lady jane;y=a;lucy in the sky".split(';') 

plain,equal = split_on_condition(src, lambda s:'=' in s) 
1

Ваш подход является лучшим. Для сортировки только в двух списках он не может стать более понятным. Если вы хотите быть один вкладыш, инкапсулировать в функции:

def classify(arguments): 
    equal, plain = [], [] 
    for arg in arguments: 
     if '=' in arg: 
      equal.append(arg) 
     else: 
      plain.append(arg) 
    return equal, plain 


equal, plain = classify(lst) 
2

Я хотел бы пойти на подходе Эден в, например,

equal = [arg for arg in arguments if '=' in arg] 
plain = [arg for arg in arguments if '=' not in arg] 
2

Я прочитал где-то здесь, что вы могли бы быть заинтересованы в решении, что будет работать на более чем двух идентификаторов (знак равенства и пробел).

Следующее решение требует только вы обновите uniques набор с все, что вы хотели бы, чтобы соответствовать, результаты помещаются в словаре списков с идентификатором в качестве ключа.

uniques = set('= ') 
matches = dict((key, []) for key in uniques) 

for arg in args: 
    key = set(arg) & uniques 
    try: 
     matches[key.pop()].append(arg) 
    except KeyError: 
     # code to handle where arg does not contain = or ' '. 

Теперь приведенный выше код предполагает, что вы будете иметь только один матч для вашего идентификатора в вашем arg. Если у вас нет arg, который выглядит так: 'John= equalspace'. Вам также нужно подумать о том, как вы хотели бы обрабатывать случаи, которые не соответствуют чему-либо в наборе (KeyError.)