Наиболее питонический способ расширить потенциально неполный список - PullRequest
8 голосов
/ 05 февраля 2009

То, что я ищу, - лучший способ сказать: «Если этот список слишком короткий, удлините его до 9 элементов и добавьте« Выбор 4 »,« Выбор 5 »и т. Д. В качестве дополнительных элементов. Также замените все элементы «None» на «Choice x». Можно заменить "" и 0 тоже.

Примером преобразования будет

['a','b',None,'c']

до

['a','b','Choice 3','c','Choice 5','Choice 6','Choice 7','Choice 8','Choice 9']

В моем исходном коде неправильно использовалась попытка / исключение и произошла ошибка, которую я не заметил; спасибо Joeforker и всем, кто указал на это. На основании комментариев я попробовал два коротких решения, которые одинаково хорошо тестируют:

def extendChoices(cList):
  for i in range(0,9):
    try:
      if cList[i] is None:
        cList[i] = "Choice %d"%(i+1)
    except IndexError:
      cList.append("Choice %d"%(i+1)

и

def extendChoices(cList):
  # Fill in any blank entries
  for i, v in enumerate(cList):
    cList[i] = v or "Choice %s" % (i+1)

  # Extend the list to 9 choices  
  for j in range(len(cList)+1, 10):
    cList.append("Choice %s" % (j))

Я думаю, что # 2 побеждает как более питонический, поэтому я буду использовать его. Это легко понять и использует общие конструкции. Разделение шагов логично и облегчает понимание с первого взгляда.

Ответы [ 20 ]

10 голосов
/ 05 февраля 2009

В отличие от zip, Python map автоматически расширяет более короткие последовательности на None.

map(lambda a, b: b if a is None else a,
    choicesTxt,
    ['Choice %i' % n for n in range(1, 10)])

Вы можете упростить лямбду до

map(lambda a, b: a or b,
    choicesTxt,
    ['Choice %i' % n for n in range(1, 10)])

, если нормально обрабатывать другие ложноподобные объекты в choicesTxt так же, как None.

7 голосов
/ 05 февраля 2009

Моей первоначальной реакцией было разделить расширение списка и «заполнение пробелов» на отдельные части следующим образом:

for i, v in enumerate(my_list):
    my_list[i] = v or "Choice %s" % (i+1)

for j in range(len(my_list)+1, 10):
    my_list.append("Choice %s" % (j))

# maybe this is nicer for the extension?
while len(my_list) < 10:
    my_list.append("Choice %s" % (len(my_list)+1))

Если вы придерживаетесь подхода try...except, поймайте конкретное исключение, как показывает Дуглас . В противном случае вы поймаете все : KeyboardInterrupts, RuntimeErrors, SyntaxErrors, .... Вы не хотите этого делать.

РЕДАКТИРОВАТЬ: исправлена ​​ошибка 1-индексированного списка - спасибо DNS !

РЕДАКТИРОВАТЬ: добавлено альтернативное расширение списка

3 голосов
/ 05 февраля 2009

Вы можете использовать карту (словарь) вместо списка:

choices_map = {1:'Choice 1', 2:'Choice 2', 3:'Choice 12'}
for key in xrange(1, 10):
    choices_map.setdefault(key, 'Choice %d'%key)

Тогда у вас есть карта, заполненная вашими данными.
Если вы хотите список вместо этого вы можете сделать:

choices = choices_map.values()
choices.sort() #if you want your list to be sorted
#In Python 2.5 and newer you can do:
choices = [choices_map[k] for k in sorted(choices_map)]
3 голосов
/ 05 февраля 2009

Я думаю, я бы сделал что-то вроде этого, но с несколькими прибавками:

for i in range(0,10):
  try:
    if choicesTxt[i] is None:
      choicesTxt[i] = "Choice %d"%i
  except IndexError:
    choicesTxt.append("Choice %d"%i)

Из которых единственными важными являются только IndexError, а не какое-либо исключение, и индексирование от 0.

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

2 голосов
/ 05 февраля 2009

Я думаю, вы должны рассматривать изменение размера массива как отдельный шаг. Для этого в случае, если массив слишком короткий, вызовите choicesTxt=choicesTxt+[None]*(10-len(choicesTxt)). Переопределение выбора None может быть выполнено с использованием списочных представлений.

2 голосов
/ 05 февраля 2009

Самый простой и самый питонический для меня это:

repl = lambda i: "Choice %d" % (i + 1) # DRY
print ([(x or repl(i)) for i, x in enumerate(aList)]
     + [repl(i) for i in xrange(len(aList), 9)])
1 голос
/ 05 февраля 2009
choices[:] = ([{False: x, True: "Choice %d" % (i + 1)}[x is None] for i, x in enumerate(choices)] +
  ["Choice %d" % (i + 1) for i in xrange(len(choices), 9)])
1 голос
/ 05 февраля 2009

Я бы сделал

for i, c in enumerate(choices):
    if c is None:
        choices[i] = 'Choice X'

choices += ['Choice %d' % (i+1) for i in range(len(choices), 10)]

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

1 голос
/ 05 февраля 2009

Мне немного непонятно, почему вы используете диапазон (1, 10); поскольку вы используете choicesTxt [i], в результате пропускается проверка None для первого элемента в вашем списке.

Кроме того, есть очевидные более простые способы сделать это, если вы создаете новый список, но вы просите специально добавить его в существующий список.

Я не думаю, что это действительно чище или быстрее, но вам стоит подумать о другом.

for i, v in enumerate(choicesTxt):
    choicesTxt[i] = v or "Choice " + str(i + 1)

choicesTxt.extend([ "Choice " + str(i) for i in range(len(choicesTxt) + 1, 10) ])
1 голос
/ 05 февраля 2009

Если вы не возражаете заменить что-либо, что оценивается как False, на «Выбор% d», то result работает для Python 2.4.

Если вы не возражаете и имеете Python 2.5 и выше, тогда используйте result2_5_plus с троичной силой if.

Если вы не любите или не можете использовать троичное выражение if, воспользуйтесь тем, что True == 1 и False == 0, используя результат x is None для индексации списка.

x = ["Blue", None, 0, "", "No, Yelloooow!"]
y = [None]*9

result = [(t or "Choice %d" % (i+1))\ 
        for i, t in enumerate(x + y[len(x):])]

result2_5_plus = [(t if t is not None else "Choice %d" % (i+1))\ 
        for i, t in enumerate(x + y[len(x):])]

result_no_ternary_if = [[t, "Choice %d" % (i+1)][t is None]\
    for i, t in enumerate(x + y[len(x):])]

['Blue', 'Choice 2', 'Choice 3', 'Choice 4', 'No, Yelloooow!', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']
['Blue', 'Choice 2', 0, '', 'No, Yelloooow!', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...