大多数pythonic方式扩展可能不完整的列表

时间:2009-02-05 14:11:32

标签: python

我正在寻找的是最佳方式,'如果此列表太短,将其延长为9个元素并添加'选择4','选择5'等作为附加元素。另外,用'Choice x'替换任何'None'元素。也可以替换“”和0。

示例转换将是

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

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

我的初始代码滥用了try / except,并且有一个我没注意到的一个错误;感谢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赢得更多pythonic,所以它是我将使用的那个。它易于理解和使用常见的结构。拆分步骤是合乎逻辑的,可以使人们更容易理解。

20 个答案:

答案 0 :(得分:10)

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)])

您可以将lambda简化为

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

如果可以在choicesTxt中处理与None相同的其他虚假对象。

答案 1 :(得分:7)

我最初的反应是将列表扩展名和“填空”填入单独的部分,如下所示:

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方法,请抓住Douglas显示的特定异常。否则,您将抓住所有内容KeyboardInterruptsRuntimeErrorsSyntaxErrors,....你不想这样做。

编辑:修复了1个索引列表错误 - 感谢DNS

编辑:添加了替代列表扩展

答案 2 :(得分:3)

您可以使用map(字典)代替list:

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 :(得分:3)

我想我会做一些非常类似的事情,但有一些整洁的事情:

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为空,那么原始的唯一真正问题是,当添加的选项将被关闭时。

答案 4 :(得分:2)

我认为你应该把调整数组大小作为一个单独的步骤。为此,如果数组太短,请调用choicesTxt=choicesTxt+[None]*(10-len(choicesTxt))。 可以使用列表推导来完成None选择重新分配。

答案 5 :(得分:2)

对我来说,最简单,最pythonic是:

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)])

答案 6 :(得分:1)

我发现当列表推导变长时,最好只使用标准for循环。 几乎和其他人一样,但无论如何:

>>> in_list = ["a","b",None,"c"]
>>> full_list = in_list + ([None] * (10 - len(in_list)))
>>> for idx, value in enumerate(full_list):
...     if value == None:
...             full_list[idx] = 'Choice %d' % (idx + 1)
...
>>> full_list
['a', 'b', 'Choice 3', 'c', 'Choice 5', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9', 'Choice 10']

答案 7 :(得分:1)

好一行:

[a or 'Choice %d' % i for a,i in map(None,["a","b",None,"c"],range(10))]

虽然那会用“Choice n”替换任何评价为False的东西(例如None,',0等)。如果yuo不想要,最好用函数替换"a or 'Choice %d' % i"

关键是可以使用参数为None的map将列表扩展到所需位置的None所需的长度。

更整洁(更pythonic)的版本将是:

def extend_choices(lst,length):
    def replace_empty(value,index):
        if value is None:
            return 'Choice %d' % index
        return value
    return [replace_empty(value,index) for value,index in map(None,lst,range(length))]

答案 8 :(得分:1)

def choice_n(index):
  return "Choice %d" % (index + 1)

def add_choices(lst, length, default=choice_n):
  """
  >>> add_choices(['a', 'b', None, 'c'], 9)
  ['a', 'b', 'Choice 3', 'c', 'Choice 5', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']
  """

  for i, v in enumerate(lst):
    if v is None:
      lst[i] = default(i)

  for i in range(len(lst), length):
    lst.append(default(i))

  return lst

if __name__ == "__main__":
  import doctest
  doctest.testmod()

答案 9 :(得分:1)

你可以通过列表理解更简单:

extendedChoices = choices + ([None] * (10 - len(choices)))
newChoices = ["Choice %d" % (i+1) if x is None else x
    for i, x in enumerate(extendedChoices)]

这会将None追加到您的选择列表中,直到它至少包含10个项目,通过结果进行枚举,如果缺少第X个元素,则插入“Choice X”。

答案 10 :(得分:1)

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)])

答案 11 :(得分:1)

我愿意

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值(不是任何评估为false的值),并在一个单独的步骤中扩展列表,我认为更清楚。

答案 12 :(得分:1)

我有点不清楚你为什么使用射程(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) ])

答案 13 :(得分:1)

如果你不介意用“Choice%d”替换任何评价为False的东西,那么result适用于Python 2.4。

如果您介意并使用Python 2.5及更高版本,那么请使用具有三元result2_5_plus功能的if

如果您不喜欢或不能使用三元if,那么请利用True == 1False == 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']

答案 14 :(得分:1)

怎么样(似乎是一个字典 - 不是列表 - 当它不完整时)

a = {1:'a', 2:None, 5:'e'} #test data
[a[x] if x in a and a[x] is not None else 'Choice %d'%x for x in xrange(1,10)]

再次编辑:如果它真的是一个列表(不是字典):

b=['a',None,'b']
[b[x] if len(b)>x and b[x] is not None else 'Choice %d'%x for x in xrange(10)]
我认为

需要Python 2.5(因为三元运算符)?

(感谢joeforker修复了它使用键1到10而不是0到10;感谢SilentGhost:in比pythonic比on_key()或len()更多

答案 15 :(得分:0)

>>> in_list = ["a","b",None,"c"]
>>> new = ['choice ' + str(i + 1) if j is None else j for i, j in enumerate(in_list)]
>>> new.extend(('choice ' +str(i + 1) for i in range(len(new), 9)))
>>> new
['a', 'b', 'choice 3', 'c', 'choice 5', 'choice 6', 'choice 7', 'choice 8', 'choice 9']

答案 16 :(得分:0)

我还建议使用xrange而不是range。 xrange函数根据需要生成数字。范围预先生成它们。对于小型设备而言,它没有太大区别,但对于大范围而言,节省的费用可能很大。

答案 17 :(得分:0)

我的两分钱......

def extendchoices(clist):
    clist.extend( [None]*(9-len(clist)) )
    for i in xrange(9):
        if clist[i] is None: clist[i] = "Choice %d"%(i+1) 

答案 18 :(得分:0)

如果可以替换任何错误值,例如''或0

>>> mylist = ['a','b',None,'c']
>>> map(lambda a,b:a or "Choice %s"%b, mylist, range(1,10))
['a', 'b', 'Choice 3', 'c', 'Choice 5', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']

如果你真的只能替换无

>>> map(lambda a,b:"Choice %s"%b if a is None else a, mylist, range(1,10))
['a', 'b', 'Choice 3', 'c', 'Choice 5', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']

答案 19 :(得分:0)

>>> my_list=['a','b',None,'c']
>>> map (lambda x,y:x or 'Choice {}'.format(y+1),my_list,range(9))
['a', 'b', 'Choice 3', 'c', 'Choice 5', 'Choice 6', 'Choice 7', 'Choice 8', 'Choice 9']