【问题标题】:How to do something only to the first item within a loop in python?如何只对python循环中的第一项做某事?
【发布时间】:2014-01-27 04:44:09
【问题描述】:

我想做一些与列表中的第一项不同的事情。这样做最pythonic的方式是什么?

for item in list:
    # only if its the first item, do something

    # otherwise do something else

【问题讨论】:

  • 使用处理第一个项目后更改的标志。

标签: python list loops


【解决方案1】:

几个选择,按 Pythonicity 降序排列:

for index, item in enumerate(lst): # note: don't use list
    if not index: # or if index == 0:
        # first item
    else:
        # other items

或者:

first = True
for item in lst:
    if first:
        first = False
        # first item 
    else:
        # other items 

或者:

for index in range(len(lst)):
    item = lst[i]
    if not index:
        # first item
    else:
        # other items

【讨论】:

  • 使用enumerate 优于其他几个选项的一个优点是,被迭代的对象是否支持索引并不重要。
  • 我喜欢枚举,但我不知道我是否会使用if not indexif index==0 更明确。
  • @adsmith:PEP 8 另有说明。并且在标准库中有恰好if not index: 的示例。
  • 所有变体都需要 if 在循环体中。非常低效
  • @volcano:真的吗?你测试过吗?因为通常情况下,至少在 CPython 中,if myint: 的成本比在迭代器上调用 next 的成本低几个数量级,所以你几乎无法测量它。如果您有一个“非常低效”的具体示例,请发布数据。
【解决方案2】:

您可以使用 iter() 在列表上创建一个迭代器,然后对其调用 next() 以获取第一个值,然后循环其余的值。我发现这是处理文件的一种非常优雅的方式,其中第一行是标题,其余的是数据,即

list_iterator = iter(lst)

# consume the first item
first_item = next(list_iterator)

# now loop on the tail
for item in list_iterator:
    print(item)

【讨论】:

  • 解释有点不对劲——你没有将列表转换为迭代器,而是在列表上创建迭代器。因效率和优雅而受到赞誉
  • 好点,我已经编辑澄清。另外我喜欢调用 iter(iter(list)) 仍然返回内部 所以你不需要知道 lst 是列表对象还是 list_iterator (或其他可迭代对象)
【解决方案3】:
do_something_with_first_item(lst[0])
for item in lst[1:]:
    do_something_else(item)

或者:

is_first_item = True
for item in lst:
    if is_first_item:
        do_something_with_first_item(item)
        is_first_item = False
    else:
        do_something_else(item)

不要使用list 作为变量名,因为这会影响内置函数list()

jonrsharpe 的答案中基于enumerate 的解决方案优于此。您可能应该改用它。

【讨论】:

    【解决方案4】:

    使用处理第一个项目后更改的标志。例如:

    first = True
    for item in my_list:
        if first:
            # Processing unique to the first item
            first = False
        else:
            # Processing unique to other items
        # Shared processing
    

    您也可以只处理第一项:

    first = my_list.pop(0)
    # Process first
    for item in my_list:
        # Process item
    
    # Add the first item back to the list at the beginning
    my_list.insert(0, first)
    

    【讨论】:

    • +!对于.pop(),老实说,这是这里最好、最干净的解决方案。
    【解决方案5】:

    jonrsharpe 使用enumerate 的第一个版本简洁明了,适用于所有可迭代对象:

    for index, item in enumerate(lst):
        if not index:
            do_something_with_first_item(item)
        else:
            do_something_else(item)
    

    senshin 使用lst[0]lst[1:] 的第一个解决方案更加简单,但仅适用于序列:

    do_something_with_first_item(lst[0])
    for item in lst[1:]:
        do_something_else(item)
    

    您可以通过直接使用迭代器获得两全其美:

    it = iter(lst)
    do_something_with_first_item(next(it))
    for item in it:
        do_something_else(item)
    

    但是,尽管它是两全其美的,但实际上并没有那么简单。如果您知道自己有一个迭代器(因此您可以跳过第一行),或者您无论如何都需要一个迭代器来执行itertools 和genexpr 和类似的东西(所以你是已经要写第一行了)。在其他情况下是否值得做更多的是风格问题。

    【讨论】:

    • 我认为对于最后一种方法,您不必知道是否有迭代器。我做了一个快速检查并在迭代器上调用 iter() 似乎返回了原始迭代器 - 即 iter(iter([1,2,3])) 和 iter([1,2,3]) 都返回一个 迭代原始列表。所以我会在每种情况下都使用这种方法——第一种是干净的,但会在循环的每次迭代中测试索引,秒需要一个可索引的对象。
    • @user2981639: 是的,如果iter(it) 是一个迭代器,它肯定会返回it——也就是说,事实上,它是迭代器定义的一部分。关键是如果你知道它是一个迭代器,你可以跳过第一行,这是最简单的解决方案;如果你有一个序列,或者不知道你有什么样的可迭代,你不能跳过第一行,所以它可能不是最简单的
    猜你喜欢
    • 2020-02-29
    • 1970-01-01
    • 1970-01-01
    • 2016-07-23
    • 1970-01-01
    • 2014-07-24
    • 1970-01-01
    • 2015-07-03
    • 1970-01-01
    相关资源
    最近更新 更多