标签归档:for-loop

当在apply中也计算出先前值时,Pandas中有没有一种方法可以使用dataframe.apply中的先前行值?

问题:当在apply中也计算出先前值时,Pandas中有没有一种方法可以使用dataframe.apply中的先前行值?

我有以下数据框:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   Nan  10
 2015-02-01     2    3   Nan  22 
 2015-02-02    10   60   Nan  280
 2015-02-03    10   100   Nan  250

要求:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   10   10
 2015-02-01     2    3   23   22
 2015-02-02    10   60   290  280
 2015-02-03    10   100  3000 250

Column C导出用于2015-01-31通过取valueD

然后,我需要使用valueC用于2015-01-31通过和乘法valueA2015-02-01添加B

我尝试使用,applyshift使用if else,这会导致出现关键错误。

I have the following dataframe:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   Nan  10
 2015-02-01     2    3   Nan  22 
 2015-02-02    10   60   Nan  280
 2015-02-03    10   100   Nan  250

Require:

 Index_Date    A    B    C    D
 ===============================
 2015-01-31    10   10   10   10
 2015-02-01     2    3   23   22
 2015-02-02    10   60   290  280
 2015-02-03    10   100  3000 250

Column C is derived for 2015-01-31 by taking value of D.

Then I need to use the value of C for 2015-01-31 and multiply by the value of A on 2015-02-01 and add B.

I have attempted an apply and a shift using an if else by this gives a key error.


回答 0

首先,创建派生值:

df.loc[0, 'C'] = df.loc[0, 'D']

然后遍历其余行并填充计算出的值:

for i in range(1, len(df)):
    df.loc[i, 'C'] = df.loc[i-1, 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']


  Index_Date   A   B    C    D
0 2015-01-31  10  10   10   10
1 2015-02-01   2   3   23   22
2 2015-02-02  10  60  290  280

First, create the derived value:

df.loc[0, 'C'] = df.loc[0, 'D']

Then iterate through the remaining rows and fill the calculated values:

for i in range(1, len(df)):
    df.loc[i, 'C'] = df.loc[i-1, 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']


  Index_Date   A   B    C    D
0 2015-01-31  10  10   10   10
1 2015-02-01   2   3   23   22
2 2015-02-02  10  60  290  280

回答 1

给定一列数字:

lst = []
cols = ['A']
for a in range(100, 105):
    lst.append([a])
df = pd.DataFrame(lst, columns=cols, index=range(5))
df

    A
0   100
1   101
2   102
3   103
4   104

您可以使用shift引用上一行:

df['Change'] = df.A - df.A.shift(1)
df

    A   Change
0   100 NaN
1   101 1.0
2   102 1.0
3   103 1.0
4   104 1.0

Given a column of numbers:

lst = []
cols = ['A']
for a in range(100, 105):
    lst.append([a])
df = pd.DataFrame(lst, columns=cols, index=range(5))
df

    A
0   100
1   101
2   102
3   103
4   104

You can reference the previous row with shift:

df['Change'] = df.A - df.A.shift(1)
df

    A   Change
0   100 NaN
1   101 1.0
2   102 1.0
3   103 1.0
4   104 1.0

回答 2

numba

对于不可矢量化的递归计算numba,使用JIT编译并与较低级别的对象配合使用,通常会带来较大的性能改进。您只需要定义一个常规for循环并使用decorator@njit或(对于旧版本)@jit(nopython=True)

对于合理大小的数据帧,与常规for循环相比,这可以将性能提高约30倍:

from numba import jit

@jit(nopython=True)
def calculator_nb(a, b, d):
    res = np.empty(d.shape)
    res[0] = d[0]
    for i in range(1, res.shape[0]):
        res[i] = res[i-1] * a[i] + b[i]
    return res

df['C'] = calculator_nb(*df[list('ABD')].values.T)

n = 10**5
df = pd.concat([df]*n, ignore_index=True)

# benchmarking on Python 3.6.0, Pandas 0.19.2, NumPy 1.11.3, Numba 0.30.1
# calculator() is same as calculator_nb() but without @jit decorator
%timeit calculator_nb(*df[list('ABD')].values.T)  # 14.1 ms per loop
%timeit calculator(*df[list('ABD')].values.T)     # 444 ms per loop

numba

For recursive calculations which are not vectorisable, numba, which uses JIT-compilation and works with lower level objects, often yields large performance improvements. You need only define a regular for loop and use the decorator @njit or (for older versions) @jit(nopython=True):

For a reasonable size dataframe, this gives a ~30x performance improvement versus a regular for loop:

from numba import jit

@jit(nopython=True)
def calculator_nb(a, b, d):
    res = np.empty(d.shape)
    res[0] = d[0]
    for i in range(1, res.shape[0]):
        res[i] = res[i-1] * a[i] + b[i]
    return res

df['C'] = calculator_nb(*df[list('ABD')].values.T)

n = 10**5
df = pd.concat([df]*n, ignore_index=True)

# benchmarking on Python 3.6.0, Pandas 0.19.2, NumPy 1.11.3, Numba 0.30.1
# calculator() is same as calculator_nb() but without @jit decorator
%timeit calculator_nb(*df[list('ABD')].values.T)  # 14.1 ms per loop
%timeit calculator(*df[list('ABD')].values.T)     # 444 ms per loop

回答 3

在numpy数组上应用递归函数将比当前答案更快。

df = pd.DataFrame(np.repeat(np.arange(2, 6),3).reshape(4,3), columns=['A', 'B', 'D'])
new = [df.D.values[0]]
for i in range(1, len(df.index)):
    new.append(new[i-1]*df.A.values[i]+df.B.values[i])
df['C'] = new

输出量

      A  B  D    C
   0  1  1  1    1
   1  2  2  2    4
   2  3  3  3   15
   3  4  4  4   64
   4  5  5  5  325

Applying the recursive function on numpy arrays will be faster than the current answer.

df = pd.DataFrame(np.repeat(np.arange(2, 6),3).reshape(4,3), columns=['A', 'B', 'D'])
new = [df.D.values[0]]
for i in range(1, len(df.index)):
    new.append(new[i-1]*df.A.values[i]+df.B.values[i])
df['C'] = new

Output

      A  B  D    C
   0  1  1  1    1
   1  2  2  2    4
   2  3  3  3   15
   3  4  4  4   64
   4  5  5  5  325

回答 4

尽管问这个问题已经有一段时间了,但我还是会发表我的答案,希望对大家有所帮助。

免责声明:我知道此解决方案不是标准的,但我认为它很好用。

import pandas as pd
import numpy as np

data = np.array([[10, 2, 10, 10],
                 [10, 3, 60, 100],
                 [np.nan] * 4,
                 [10, 22, 280, 250]]).T
idx = pd.date_range('20150131', end='20150203')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df
               A    B     C    D
 =================================
 2015-01-31    10   10    NaN  10
 2015-02-01    2    3     NaN  22 
 2015-02-02    10   60    NaN  280
 2015-02-03    10   100   NaN  250

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)
df
               A    B     C     D
 =================================
 2015-01-31    10   10    10    10
 2015-02-01    2    3     23    22 
 2015-02-02    10   60    290   280
 2015-02-03    10   100   3000  250

因此,基本上,我们使用applyfrom from pandas和全局变量的帮助来跟踪先前的计算值。


for循环时间比较:

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

df.loc['2015-01-31', 'C'] = df.loc['2015-01-31', 'D']

%%timeit
for i in df.loc['2015-02-01':].index.date:
    df.loc[i, 'C'] = df.loc[(i - pd.DateOffset(days=1)).date(), 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']

每个循环3.2 s±114毫秒(平均±标准偏差,共运行7次,每个循环1次)

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value

%%timeit
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)

每个循环1.82 s±64.4 ms(平均±标准偏差,共7次运行,每个循环1次)

因此平均快0.57倍。

Although it has been a while since this question was asked, I will post my answer hoping it helps somebody.

Disclaimer: I know this solution is not standard, but I think it works well.

import pandas as pd
import numpy as np

data = np.array([[10, 2, 10, 10],
                 [10, 3, 60, 100],
                 [np.nan] * 4,
                 [10, 22, 280, 250]]).T
idx = pd.date_range('20150131', end='20150203')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df
               A    B     C    D
 =================================
 2015-01-31    10   10    NaN  10
 2015-02-01    2    3     NaN  22 
 2015-02-02    10   60    NaN  280
 2015-02-03    10   100   NaN  250

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)
df
               A    B     C     D
 =================================
 2015-01-31    10   10    10    10
 2015-02-01    2    3     23    22 
 2015-02-02    10   60    290   280
 2015-02-03    10   100   3000  250

So basically we use a apply from pandas and the help of a global variable that keeps track of the previous calculated value.


Time comparison with a for loop:

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

df.loc['2015-01-31', 'C'] = df.loc['2015-01-31', 'D']

%%timeit
for i in df.loc['2015-02-01':].index.date:
    df.loc[i, 'C'] = df.loc[(i - pd.DateOffset(days=1)).date(), 'C'] * df.loc[i, 'A'] + df.loc[i, 'B']

3.2 s ± 114 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

data = np.random.random(size=(1000, 4))
idx = pd.date_range('20150131', end='20171026')
df = pd.DataFrame(data=data, columns=list('ABCD'), index=idx)
df.C = np.nan

def calculate(mul, add):
    global value
    value = value * mul + add
    return value

value = df.loc['2015-01-31', 'D']
df.loc['2015-01-31', 'C'] = value

%%timeit
df.loc['2015-02-01':, 'C'] = df.loc['2015-02-01':].apply(lambda row: calculate(*row[['A', 'B']]), axis=1)

1.82 s ± 64.4 ms per loop (mean ± std. dev. of 7 runs, 1 loop each)

So 0.57 times faster on average.


回答 5

通常,避免显式循环的关键是在rowindex-1 == rowindex上联接(合并)数据框的2个实例。

然后,您将拥有一个包含r和r-1行的大数据框,可以在其中执行df.apply()函数。

但是,创建大型数据集的开销可能抵消了并行处理的好处。

马丁

In general, the key to avoiding an explicit loop would be to join (merge) 2 instances of the dataframe on rowindex-1==rowindex.

Then you would have a big dataframe containing rows of r and r-1, from where you could do a df.apply() function.

However the overhead of creating the large dataset may offset the benefits of parallel processing…

HTH Martin


单行嵌套循环

问题:单行嵌套循环

在转置矩阵的python中编写此函数:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

在此过程中,我意识到我不完全了解嵌套在循环中的单行如何执行。请回答以下问题,以帮助我理解:

  1. 此for循环执行的顺序是什么?
  2. 如果我有一个三重嵌套的for循环,它将执行什么顺序?
  3. 等于未嵌套for循环等于什么?

鉴于

[ function(i,j) for i,j in object ]
  1. 为了将其用于循环结构,对象必须是哪种类型?
  2. 将i和j分配给object中的元素的顺序是什么?
  3. 可以用不同的for循环结构模拟吗?
  4. 可以将此for循环嵌套在相似或不同的for循环结构中吗?看起来如何?

附加信息也将不胜感激。

Wrote this function in python that transposes a matrix:

def transpose(m):
    height = len(m)
    width = len(m[0])
    return [ [ m[i][j] for i in range(0, height) ] for j in range(0, width) ]

In the process I realized I don’t fully understand how single line nested for loops execute. Please help me understand by answering the following questions:

  1. What is the order in which this for loop executes?
  2. If I had a triple nested for loop, what order would it execute?
  3. What would be equal the equal unnested for loop?

Given,

[ function(i,j) for i,j in object ]
  1. What type must object be in order to use this for loop structure?
  2. What is the order in which i and j are assigned to elements in object?
  3. Can it be simulated by a different for loop structure?
  4. Can this for loop be nested with a similar or different structure for loop? And how would it look?

Additional information is appreciated as well.


回答 0

最好的信息来源是有关列表理解官方Python教程。列表理解与for循环几乎相同(当然,任何列表理解都可以写为for循环),但它们通常比使用for循环更快。

在教程中查看这个更长的列表理解(该if部分过滤了理解,只有通过if语句的部分才被传递到列表理解的最后一部分(此处(x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

它与嵌套的for循环完全相同(并且,如本教程所述,请注意for和if的顺序如何相同)。

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

列表理解和for循环之间的主要区别在于for循环的最后部分(您在其中进行操作)始于而不是结束。

关于您的问题:

为了将其用于循环结构,对象必须是哪种类型?

一个可迭代的。可以生成(有限)元素集的任何对象。这些包括任何容器,列表,集合,生成器等。

将i和j分配给object中的元素的顺序是什么?

它们的分配顺序与从每个列表生成的顺序完全相同,就好像它们在嵌套的for循环中一样(对于第一次理解,您将为i获得1个元素,然后将j中的每个值,第2个元素赋给i,然后来自j等的每个值)

可以用不同的for循环结构模拟吗?

是的,上面已经显示了。

可以将此for循环嵌套在相似或不同的for循环结构中吗?看起来如何?

是的,但这不是一个好主意。例如,在此处为您提供字符列表:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]

The best source of information is the official Python tutorial on list comprehensions. List comprehensions are nearly the same as for loops (certainly any list comprehension can be written as a for-loop) but they are often faster than using a for loop.

Look at this longer list comprehension from the tutorial (the if part filters the comprehension, only parts that pass the if statement are passed into the final part of the list comprehension (here (x,y)):

>>> [(x, y) for x in [1,2,3] for y in [3,1,4] if x != y]
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

It’s exactly the same as this nested for loop (and, as the tutorial says, note how the order of for and if are the same).

>>> combs = []
>>> for x in [1,2,3]:
...     for y in [3,1,4]:
...         if x != y:
...             combs.append((x, y))
...
>>> combs
[(1, 3), (1, 4), (2, 3), (2, 1), (2, 4), (3, 1), (3, 4)]

The major difference between a list comprehension and a for loop is that the final part of the for loop (where you do something) comes at the beginning rather than at the end.

On to your questions:

What type must object be in order to use this for loop structure?

An iterable. Any object that can generate a (finite) set of elements. These include any container, lists, sets, generators, etc.

What is the order in which i and j are assigned to elements in object?

They are assigned in exactly the same order as they are generated from each list, as if they were in a nested for loop (for your first comprehension you’d get 1 element for i, then every value from j, 2nd element into i, then every value from j, etc.)

Can it be simulated by a different for loop structure?

Yes, already shown above.

Can this for loop be nested with a similar or different structure for loop? And how would it look?

Sure, but it’s not a great idea. Here, for example, gives you a list of lists of characters:

[[ch for ch in word] for word in ("apple", "banana", "pear", "the", "hello")]

回答 1

您可能对感兴趣itertools.product,它会从您传递的所有可迭代对象中返回一个可迭代的值元组。也就是说,itertools.product(A, B)产生形式的所有值(a, b),其中a值来自Ab值来自B。例如:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

打印:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

请注意,传递给最终参数的参数itertools.product是“内部” 参数。通常等于itertools.product(a0, a1, ... an)[(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]

You might be interested in itertools.product, which returns an iterable yielding tuples of values from all the iterables you pass it. That is, itertools.product(A, B) yields all values of the form (a, b), where the a values come from A and the b values come from B. For example:

import itertools

A = [50, 60, 70]
B = [0.1, 0.2, 0.3, 0.4]

print [a + b for a, b in itertools.product(A, B)]

This prints:

[50.1, 50.2, 50.3, 50.4, 60.1, 60.2, 60.3, 60.4, 70.1, 70.2, 70.3, 70.4]

Notice how the final argument passed to itertools.product is the “inner” one. Generally, itertools.product(a0, a1, ... an) is equal to [(i0, i1, ... in) for in in an for in-1 in an-1 ... for i0 in a0]


回答 2

首先,您的第一个代码本身并不使用for循环,而是使用列表推导

  1. 相当于

    对于范围(0,宽度)中的j:对于范围(0,高度)中的i:m [i] [j]

  2. 大致相同,它通常像for循环一样从右到左嵌套。但是列表理解语法更复杂。

  3. 我不确定这个问题在问什么


  1. 产生可迭代对象且恰好产生两个对象的任何可迭代对象(实际上[(1,2),'ab']是有效的)

  2. 对象在迭代时产生的顺序。i转到第一个Yield,j第二个。

  3. 是的,但是不那么漂亮。我相信它在功能上等同于:

    l = list()
    对于对象中的i,j:
        l.append(function(i,j))
    

    甚至更好地使用map

    map(function, object)

    不过,当然功能必须得到ij本身。

  4. 这不是3个相同的问题吗?

First of all, your first code doesn’t use a for loop per se, but a list comprehension.

  1. Would be equivalent to

    for j in range(0, width): for i in range(0, height): m[i][j]

  2. Much the same way, it generally nests like for loops, right to left. But list comprehension syntax is more complex.

  3. I’m not sure what this question is asking


  1. Any iterable object that yields iterable objects that yield exactly two objects (what a mouthful – i.e [(1,2),'ab'] would be valid )

  2. The order in which the object yields upon iteration. i goes to the first yield, j the second.

  3. Yes, but not as pretty. I believe it is functionally equivalent to:

    l = list()
    for i,j in object:
        l.append(function(i,j))
    

    or even better use map:

    map(function, object)
    

    But of course function would have to get i, j itself.

  4. Isn’t this the same question as 3?


回答 3

您可以使用zip函数在同一行中使用两个for循环

码:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

输出:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

因此,通过使用zip函数,我们可以使用两个for循环,也可以迭代同一行中的两个列表。

You can use two for loops in same line by using zip function

Code:

list1 = ['Abbas', 'Ali', 'Usman']
list2 = ['Kamran', 'Asgar', 'Hamza', 'Umer']
list3 = []
for i,j in zip(list1,list2):
    list3.append(i)
    list3.append(j)
print(list3)

Output:

['Abbas', 'Kamran', 'Ali', 'Asgar', 'Usman', 'Hamza']

So, by using zip function, we can use two for loops or we can iterate two lists in same row.


回答 4

下面的代码提供了嵌套循环的最佳示例,同时使用两个for循环时,请记住第一个循环的输出是第二个循环的输入。使用嵌套循环时,循环终止也很重要

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8

Below code for best examples for nested loops, while using two for loops please remember the output of the first loop is input for the second loop. Loop termination also important while using the nested loops

for x in range(1, 10, 1):
     for y in range(1,x):
             print y,
        print
OutPut :
1
1 2
1 2 3
1 2 3 4
1 2 3 4 5
1 2 3 4 5 6
1 2 3 4 5 6 7
1 2 3 4 5 6 7 8

如何在列表理解Python中构建两个for循环

问题:如何在列表理解Python中构建两个for循环

我有两个清单如下

tags = [u'man', u'you', u'are', u'awesome']
entries = [[u'man', u'thats'],[ u'right',u'awesome']]

我想提取物项从entries当他们在tags

result = []

for tag in tags:
    for entry in entries:
        if tag in entry:
            result.extend(entry)

如何将两个循环写为单行列表理解?

I have two lists as below

tags = [u'man', u'you', u'are', u'awesome']
entries = [[u'man', u'thats'],[ u'right',u'awesome']]

I want to extract entries from entries when they are in tags:

result = []

for tag in tags:
    for entry in entries:
        if tag in entry:
            result.extend(entry)

How can I write the two loops as a single line list comprehension?


回答 0

应该这样做:

[entry for tag in tags for entry in entries if tag in entry]

This should do it:

[entry for tag in tags for entry in entries if tag in entry]

回答 1

记住这一点的最好方法是,列表理解中for循环的顺序基于它们在传统循环方法中出现的顺序。最外面的循环先到,然后是内部循环。

因此,等效列表理解为:

[entry for tag in tags for entry in entries if tag in entry]

通常,if-else语句位于第一个for循环之前,如果只有一条if语句,它将位于结尾。例如,如果您想添加一个空列表,如果tag没有输入,则可以这样:

[entry if tag in entry else [] for tag in tags for entry in entries]

The best way to remember this is that the order of for loop inside the list comprehension is based on the order in which they appear in traditional loop approach. Outer most loop comes first, and then the inner loops subsequently.

So, the equivalent list comprehension would be:

[entry for tag in tags for entry in entries if tag in entry]

In general, if-else statement comes before the first for loop, and if you have just an if statement, it will come at the end. For e.g, if you would like to add an empty list, if tag is not in entry, you would do it like this:

[entry if tag in entry else [] for tag in tags for entry in entries]

回答 2

适当的LC将是

[entry for tag in tags for entry in entries if tag in entry]

LC中循环的顺序类似于嵌套循环中的顺序,if语句移至末尾,条件表达式移至开始,例如

[a if a else b for a in sequence]

观看演示-

>>> tags = [u'man', u'you', u'are', u'awesome']
>>> entries = [[u'man', u'thats'],[ u'right',u'awesome']]
>>> [entry for tag in tags for entry in entries if tag in entry]
[[u'man', u'thats'], [u'right', u'awesome']]
>>> result = []
    for tag in tags:
        for entry in entries:
            if tag in entry:
                result.append(entry)


>>> result
[[u'man', u'thats'], [u'right', u'awesome']]

编辑 -由于您需要将结果展平,因此可以使用类似的列表理解,然后展平结果。

>>> result = [entry for tag in tags for entry in entries if tag in entry]
>>> from itertools import chain
>>> list(chain.from_iterable(result))
[u'man', u'thats', u'right', u'awesome']

加起来,你可以做

>>> list(chain.from_iterable(entry for tag in tags for entry in entries if tag in entry))
[u'man', u'thats', u'right', u'awesome']

您在此处使用生成器表达式,而不是列表推导。(也完全匹配79个字符的限制(无list呼叫))

The appropriate LC would be

[entry for tag in tags for entry in entries if tag in entry]

The order of the loops in the LC is similar to the ones in nested loops, the if statements go to the end and the conditional expressions go in the beginning, something like

[a if a else b for a in sequence]

See the Demo –

>>> tags = [u'man', u'you', u'are', u'awesome']
>>> entries = [[u'man', u'thats'],[ u'right',u'awesome']]
>>> [entry for tag in tags for entry in entries if tag in entry]
[[u'man', u'thats'], [u'right', u'awesome']]
>>> result = []
    for tag in tags:
        for entry in entries:
            if tag in entry:
                result.append(entry)


>>> result
[[u'man', u'thats'], [u'right', u'awesome']]

EDIT – Since, you need the result to be flattened, you could use a similar list comprehension and then flatten the results.

>>> result = [entry for tag in tags for entry in entries if tag in entry]
>>> from itertools import chain
>>> list(chain.from_iterable(result))
[u'man', u'thats', u'right', u'awesome']

Adding this together, you could just do

>>> list(chain.from_iterable(entry for tag in tags for entry in entries if tag in entry))
[u'man', u'thats', u'right', u'awesome']

You use a generator expression here instead of a list comprehension. (Perfectly matches the 79 character limit too (without the list call))


回答 3

tags = [u'man', u'you', u'are', u'awesome']
entries = [[u'man', u'thats'],[ u'right',u'awesome']]

result = []
[result.extend(entry) for tag in tags for entry in entries if tag in entry]

print(result)

输出:

['man', 'thats', 'right', 'awesome']
tags = [u'man', u'you', u'are', u'awesome']
entries = [[u'man', u'thats'],[ u'right',u'awesome']]

result = []
[result.extend(entry) for tag in tags for entry in entries if tag in entry]

print(result)

Output:

['man', 'thats', 'right', 'awesome']

回答 4

理解上,嵌套列表迭代应遵循与forbriced for循环相同的顺序。

为了理解,我们将以NLP为例。您想从句子列表中创建所有单词的列表,其中每个句子都是单词列表。

>>> list_of_sentences = [['The','cat','chases', 'the', 'mouse','.'],['The','dog','barks','.']]
>>> all_words = [word for sentence in list_of_sentences for word in sentence]
>>> all_words
['The', 'cat', 'chases', 'the', 'mouse', '.', 'The', 'dog', 'barks', '.']

要删除重复的单词,可以使用集合{}代替列表[]

>>> all_unique_words = list({word for sentence in list_of_sentences for word in sentence}]
>>> all_unique_words
['.', 'dog', 'the', 'chase', 'barks', 'mouse', 'The', 'cat']

或申请 list(set(all_words))

>>> all_unique_words = list(set(all_words))
['.', 'dog', 'the', 'chases', 'barks', 'mouse', 'The', 'cat']

In comprehension, the nested lists iteration should follow the same order than the equivalent imbricated for loops.

To understand, we will take a simple example from NLP. You want to create a list of all words from a list of sentences where each sentence is a list of words.

>>> list_of_sentences = [['The','cat','chases', 'the', 'mouse','.'],['The','dog','barks','.']]
>>> all_words = [word for sentence in list_of_sentences for word in sentence]
>>> all_words
['The', 'cat', 'chases', 'the', 'mouse', '.', 'The', 'dog', 'barks', '.']

To remove the repeated words, you can use a set {} instead of a list []

>>> all_unique_words = list({word for sentence in list_of_sentences for word in sentence}]
>>> all_unique_words
['.', 'dog', 'the', 'chase', 'barks', 'mouse', 'The', 'cat']

or apply list(set(all_words))

>>> all_unique_words = list(set(all_words))
['.', 'dog', 'the', 'chases', 'barks', 'mouse', 'The', 'cat']

回答 5

return=[entry for tag in tags for entry in entries if tag in entry for entry in entry]
return=[entry for tag in tags for entry in entries if tag in entry for entry in entry]

如何在for循环中注释类型

问题:如何在for循环中注释类型

我想在for-loop中注释变量的类型。我尝试了这个:

for i: int in range(5):
    pass

但这显然没有用。

我期望在PyCharm 2016.3.2中能够自动完成工作。像这样的预注释:

i: int
for i in range(5):
    pass

没有帮助。

适用于PyCharm> = 2017.1的PS预注释作品

I want to annotate a type of a variable in a for-loop. I tried this:

for i: int in range(5):
    pass

But it didn’t work, obviously.

What I expect is working autocomplete in PyCharm 2016.3.2. Pre-annotation like this:

i: int
for i in range(5):
    pass

doesn’t help.

P.S. Pre-annotation works for PyCharm >= 2017.1


回答 0

根据PEP 526,这是不允许的:

另外,不能注释forwith 语句中使用的变量。可以像元组拆包一样提前注释它们

在循环之前对其进行注释:

i: int
for i in range(5):
    pass

PyCharm 2018.1及更高版本现在可以识别循环内变量的类型。较早的PyCharm版本不支持此功能。

According to PEP 526, this is not allowed:

In addition, one cannot annotate variables used in a for or with statement; they can be annotated ahead of time, in a similar manner to tuple unpacking

Annotate it before the loop:

i: int
for i in range(5):
    pass

PyCharm 2018.1 and up now recognizes the type of the variable inside the loop. This was not supported in older PyCharm versions.


回答 1

我不知道此解决方案是否与PEP兼容,或者仅仅是PyCharm的功能,但我使它像这样工作

for i in range(5): #type: int
  pass

我正在使用Pycharm Community Edition 2016.2.1

I don’t know if this solution is PEP compatible or just a feature of PyCharm but I made it work like this

for i in range(5): #type: int
  pass

and I’m using Pycharm Community Edition 2016.2.1


回答 2

这对我在PyCharm(使用Python 3.6)中的效果很好

for i in range(5):
    i: int = i
    pass

This works well for my in PyCharm (using Python 3.6)

for i in range(5):
    i: int = i
    pass

回答 3

这里的回答都没有用,只是说不能。甚至接受的答案也使用PEP 526文档中的语法,这不是有效的python语法。如果您尝试输入

x: int

您会看到这是一个语法错误。

这是一个有用的解决方法:

for __x in range(5):
    x = __x  # type: int
    print(x)

做您的工作x。PyCharm可以识别其类型,并且可以自动完成。

None of the responses here were useful, except to say that you can’t. Even the accepted answer uses syntax from the PEP 526 document, which isn’t valid python syntax. If you try to type in

x: int

You’ll see it’s a syntax error.

Here is a useful workaround:

for __x in range(5):
    x = __x  # type: int
    print(x)

Do your work with x. PyCharm recognizes its type, and autocomplete works.


pythonic的方式做N次没有索引变量?

问题:pythonic的方式做N次没有索引变量?

我每天都越来越喜欢python。

今天,我正在编写一些代码,例如:

for i in xrange(N):
    do_something()

我必须做N次。但是每次都不依赖于i(索引变量)的值。我意识到我正在创建一个我从未使用过的变量(i),并且我想:“无疑,这是一种更加Python化的方法,不需要那个无用的索引变量。”

所以…问题是:您知道如何以更(pythonic)漂亮的方式完成此简单任务吗?

Every day I love python more and more.

Today, I was writing some code like:

for i in xrange(N):
    do_something()

I had to do something N times. But each time didn’t depend on the value of i (index variable). I realized that I was creating a variable I never used (i), and I thought “There surely is a more pythonic way of doing this without the need for that useless index variable.”

So… the question is: do you know how to do this simple task in a more (pythonic) beautiful way?


回答 0

比循环更快的方法xrange(N)是:

import itertools

for _ in itertools.repeat(None, N):
    do_something()

A slightly faster approach than looping on xrange(N) is:

import itertools

for _ in itertools.repeat(None, N):
    do_something()

回答 1

使用_变量,正如我在问这个问题时所了解到的,例如:

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product

Use the _ variable, as I learned when I asked this question, for example:

# A long way to do integer exponentiation
num = 2
power = 3
product = 1
for _ in xrange(power):
    product *= num
print product

回答 2

我只是使用for _ in range(n),这很重要。它会在Python 2中生成大量数字的整个列表,但是如果您使用的是Python 3,这不是问题。

I just use for _ in range(n), it’s straight to the point. It’s going to generate the entire list for huge numbers in Python 2, but if you’re using Python 3 it’s not a problem.


回答 3

由于函数是一等公民,因此您可以编写小型包装器(来自Alex的回答)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

那么您可以将函数作为参数传递。

since function is first-class citizen, you can write small wrapper (from Alex answers)

def repeat(f, N):
    for _ in itertools.repeat(None, N): f()

then you can pass function as argument.


回答 4

_与x相同。但是,这是一个python惯用法,用于指示您不打算使用的标识符。在python中,这些标识符不会像其他语言中的变量那样占用内存或分配空间。很容易忘记这一点。它们只是指向对象的名称,在这种情况下,每次迭代都是一个整数。

The _ is the same thing as x. However it’s a python idiom that’s used to indicate an identifier that you don’t intend to use. In python these identifiers don’t takes memor or allocate space like variables do in other languages. It’s easy to forget that. They’re just names that point to objects, in this case an integer on each iteration.


回答 5

我发现各种答案确实很不错(尤其是Alex Martelli的答案),但是我想直接量化性能,因此我编写了以下脚本:

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __name__ == '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

我还提出了另一种解决方案,该解决方案基于Martelli的解决方案,并用于map()调用有效负载函数。好的,我有点作弊,因为我可以自由地使有效负载接受被丢弃的参数:我不知道是否有解决方法。不过,结果如下:

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

因此使用map会比loop的标准提高约30%,比Martelli的标准提高19%。

I found the various answers really elegant (especially Alex Martelli’s) but I wanted to quantify performance first hand, so I cooked up the following script:

from itertools import repeat
N = 10000000

def payload(a):
    pass

def standard(N):
    for x in range(N):
        payload(None)

def underscore(N):
    for _ in range(N):
        payload(None)

def loopiter(N):
    for _ in repeat(None, N):
        payload(None)

def loopiter2(N):
    for _ in map(payload, repeat(None, N)):
        pass

if __name__ == '__main__':
    import timeit
    print("standard: ",timeit.timeit("standard({})".format(N),
        setup="from __main__ import standard", number=1))
    print("underscore: ",timeit.timeit("underscore({})".format(N),
        setup="from __main__ import underscore", number=1))
    print("loopiter: ",timeit.timeit("loopiter({})".format(N),
        setup="from __main__ import loopiter", number=1))
    print("loopiter2: ",timeit.timeit("loopiter2({})".format(N),
        setup="from __main__ import loopiter2", number=1))

I also came up with an alternative solution that builds on Martelli’s one and uses map() to call the payload function. OK, I cheated a bit in that I took the freedom of making the payload accept a parameter that gets discarded: I don’t know if there is a way around this. Nevertheless, here are the results:

standard:  0.8398549720004667
underscore:  0.8413165839992871
loopiter:  0.7110594899968419
loopiter2:  0.5891903560004721

so using map yields an improvement of approximately 30% over the standard for loop and an extra 19% over Martelli’s.


回答 6

假设您已将do_something定义为一个函数,并且您想执行N次。也许您可以尝试以下方法:

todos = [do_something] * N  
for doit in todos:  
    doit()

Assume that you’ve defined do_something as a function, and you’d like to perform it N times. Maybe you can try the following:

todos = [do_something] * N  
for doit in todos:  
    doit()

回答 7

一个简单的while循环呢?

while times > 0:
    do_something()
    times -= 1

您已经有了变量;为什么不使用它?

What about a simple while loop?

while times > 0:
    do_something()
    times -= 1

You already have the variable; why not use it?


列表理解和功能比“ for循环”快吗?

问题:列表理解和功能比“ for循环”快吗?

在Python的性能方面,是一个列表理解或功能,如map()filter()reduce()比for循环快?从技术上讲,为什么它们以C速度运行,而for循环以python虚拟机速度运行

假设在我正在开发的游戏中,我需要使用for循环绘制复杂而庞大的地图。这个问题肯定是相关的,例如,如果列表理解确实确实更快,那么它将是避免滞后的更好选择(尽管代码具有视觉上的复杂性)。

In terms of performance in Python, is a list-comprehension, or functions like map(), filter() and reduce() faster than a for loop? Why, technically, they run in a C speed, while the for loop runs in the python virtual machine speed?.

Suppose that in a game that I’m developing I need to draw complex and huge maps using for loops. This question would be definitely relevant, for if a list-comprehension, for example, is indeed faster, it would be a much better option in order to avoid lags (Despite the visual complexity of the code).


回答 0

以下是粗略的准则和基于经验的有根据的猜测。您应该timeit或配置您的具体用例以获得确切的数字,并且这些数字有时可能与以下内容不一致。

列表理解通常比精确等效的for循环(实际上是构建列表)要快一点,这很可能是因为它不必append在每次迭代时都查找列表及其方法。但是,列表理解仍然会执行字节码级别的循环:

>>> dis.dis(<the code object for `[x for x in range(10)]`>)
 1           0 BUILD_LIST               0
             3 LOAD_FAST                0 (.0)
       >>    6 FOR_ITER                12 (to 21)
             9 STORE_FAST               1 (x)
            12 LOAD_FAST                1 (x)
            15 LIST_APPEND              2
            18 JUMP_ABSOLUTE            6
       >>   21 RETURN_VALUE

由于创建和扩展列表的开销很大,因此使用列表推导代替构建列表的循环,无意义地累积无意义的值的列表然后将其扔掉通常会较慢。列表理解并不是比一个好的旧循环本质上更快的魔术。

至于功能列表处理功能:虽然这些都是用C语言编写,并可能超越Python编写的相同的功能,它们是不是一定是最快的选择。如果该函数也是用C编写的,则可以提高速度。但是在大多数情况下,使用lambda(或其他Python函数)重复设置Python堆栈框架等开销会消耗掉所有的节省。在没有函数调用的情况下,简单地在线完成相同的工作(例如,用列表理解代替mapor filter)通常会稍快一些。

假设在我正在开发的游戏中,我需要使用for循环绘制复杂而庞大的地图。这个问题肯定是相关的,例如,如果列表理解确实确实更快,那么它将是避免滞后的更好选择(尽管代码具有视觉上的复杂性)。

很有可能,如果用良好的非“优化” Python编写时这样的代码还不够快,那么就没有足够的Python级微优化可以使它足够快了,您应该开始考虑降级为C。微观优化通常可以大大加快Python代码的速度,对此(绝对值)的限制很低。而且,即使在达到极限之前,咬住子弹并写一些C语言也变得更具成本效益(加速15%,加速300%)。

The following are rough guidelines and educated guesses based on experience. You should timeit or profile your concrete use case to get hard numbers, and those numbers may occasionally disagree with the below.

A list comprehension is usually a tiny bit faster than the precisely equivalent for loop (that actually builds a list), most likely because it doesn’t have to look up the list and its append method on every iteration. However, a list comprehension still does a bytecode-level loop:

>>> dis.dis(<the code object for `[x for x in range(10)]`>)
 1           0 BUILD_LIST               0
             3 LOAD_FAST                0 (.0)
       >>    6 FOR_ITER                12 (to 21)
             9 STORE_FAST               1 (x)
            12 LOAD_FAST                1 (x)
            15 LIST_APPEND              2
            18 JUMP_ABSOLUTE            6
       >>   21 RETURN_VALUE

Using a list comprehension in place of a loop that doesn’t build a list, nonsensically accumulating a list of meaningless values and then throwing the list away, is often slower because of the overhead of creating and extending the list. List comprehensions aren’t magic that is inherently faster than a good old loop.

As for functional list processing functions: While these are written in C and probably outperform equivalent functions written in Python, they are not necessarily the fastest option. Some speed up is expected if the function is written in C too. But most cases using a lambda (or other Python function), the overhead of repeatedly setting up Python stack frames etc. eats up any savings. Simply doing the same work in-line, without function calls (e.g. a list comprehension instead of map or filter) is often slightly faster.

Suppose that in a game that I’m developing I need to draw complex and huge maps using for loops. This question would be definitely relevant, for if a list-comprehension, for example, is indeed faster, it would be a much better option in order to avoid lags (Despite the visual complexity of the code).

Chances are, if code like this isn’t already fast enough when written in good non-“optimized” Python, no amount of Python level micro optimization is going to make it fast enough and you should start thinking about dropping to C. While extensive micro optimizations can often speed up Python code considerably, there is a low (in absolute terms) limit to this. Moreover, even before you hit that ceiling, it becomes simply more cost efficient (15% speedup vs. 300% speed up with the same effort) to bite the bullet and write some C.


回答 1

如果查看python.org上信息,则可以看到以下摘要:

Version Time (seconds)
Basic loop 3.47
Eliminate dots 2.45
Local variable & no dots 1.79
Using map function 0.54

但是您确实应该详细阅读以上文章,以了解造成性能差异的原因。

我也强烈建议您使用timeit对代码计时。在一天的结束时,可能会出现例如for在满足条件时需要跳出循环的情况。它可能比调用找出结果更快map

If you check the info on python.org, you can see this summary:

Version Time (seconds)
Basic loop 3.47
Eliminate dots 2.45
Local variable & no dots 1.79
Using map function 0.54

But you really should read the above article in details to understand the cause of the performance difference.

I also strongly suggest you should time your code by using timeit. At the end of the day, there can be a situation where, for example, you may need to break out of for loop when a condition is met. It could potentially be faster than finding out the result by calling map.


回答 2

你具体问左右map()filter()reduce(),但我相信你想了解一般的函数式编程。在对一组点中所有点之间的距离进行计算的问题上进行了自我测试之后,结果表明,函数编程(使用starmap内置itertools模块中的函数)比for循环要慢一些(使用1.25倍的时间)。事实)。这是我使用的示例代码:

import itertools, time, math, random

class Point:
    def __init__(self,x,y):
        self.x, self.y = x, y

point_set = (Point(0, 0), Point(0, 1), Point(0, 2), Point(0, 3))
n_points = 100
pick_val = lambda : 10 * random.random() - 5
large_set = [Point(pick_val(), pick_val()) for _ in range(n_points)]
    # the distance function
f_dist = lambda x0, x1, y0, y1: math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
    # go through each point, get its distance from all remaining points 
f_pos = lambda p1, p2: (p1.x, p2.x, p1.y, p2.y)

extract_dists = lambda x: itertools.starmap(f_dist, 
                          itertools.starmap(f_pos, 
                          itertools.combinations(x, 2)))

print('Distances:', list(extract_dists(point_set)))

t0_f = time.time()
list(extract_dists(large_set))
dt_f = time.time() - t0_f

功能版本是否比程序版本更快?

def extract_dists_procedural(pts):
    n_pts = len(pts)
    l = []    
    for k_p1 in range(n_pts - 1):
        for k_p2 in range(k_p1, n_pts):
            l.append((pts[k_p1].x - pts[k_p2].x) ** 2 +
                     (pts[k_p1].y - pts[k_p2].y) ** 2)
    return l

t0_p = time.time()
list(extract_dists_procedural(large_set)) 
    # using list() on the assumption that
    # it eats up as much time as in the functional version

dt_p = time.time() - t0_p

f_vs_p = dt_p / dt_f
if f_vs_p >= 1.0:
    print('Time benefit of functional progamming:', f_vs_p, 
          'times as fast for', n_points, 'points')
else:
    print('Time penalty of functional programming:', 1 / f_vs_p, 
          'times as slow for', n_points, 'points')

You ask specifically about map(), filter() and reduce(), but I assume you want to know about functional programming in general. Having tested this myself on the problem of computing distances between all points within a set of points, functional programming (using the starmap function from the built-in itertools module) turned out to be slightly slower than for-loops (taking 1.25 times as long, in fact). Here is the sample code I used:

import itertools, time, math, random

class Point:
    def __init__(self,x,y):
        self.x, self.y = x, y

point_set = (Point(0, 0), Point(0, 1), Point(0, 2), Point(0, 3))
n_points = 100
pick_val = lambda : 10 * random.random() - 5
large_set = [Point(pick_val(), pick_val()) for _ in range(n_points)]
    # the distance function
f_dist = lambda x0, x1, y0, y1: math.sqrt((x0 - x1) ** 2 + (y0 - y1) ** 2)
    # go through each point, get its distance from all remaining points 
f_pos = lambda p1, p2: (p1.x, p2.x, p1.y, p2.y)

extract_dists = lambda x: itertools.starmap(f_dist, 
                          itertools.starmap(f_pos, 
                          itertools.combinations(x, 2)))

print('Distances:', list(extract_dists(point_set)))

t0_f = time.time()
list(extract_dists(large_set))
dt_f = time.time() - t0_f

Is the functional version faster than the procedural version?

def extract_dists_procedural(pts):
    n_pts = len(pts)
    l = []    
    for k_p1 in range(n_pts - 1):
        for k_p2 in range(k_p1, n_pts):
            l.append((pts[k_p1].x - pts[k_p2].x) ** 2 +
                     (pts[k_p1].y - pts[k_p2].y) ** 2)
    return l

t0_p = time.time()
list(extract_dists_procedural(large_set)) 
    # using list() on the assumption that
    # it eats up as much time as in the functional version

dt_p = time.time() - t0_p

f_vs_p = dt_p / dt_f
if f_vs_p >= 1.0:
    print('Time benefit of functional progamming:', f_vs_p, 
          'times as fast for', n_points, 'points')
else:
    print('Time penalty of functional programming:', 1 / f_vs_p, 
          'times as slow for', n_points, 'points')

回答 3

我写了一个简单的脚本来测试速度,这就是我发现的结果。实际上对于我来说,for循环最快。真的让我感到惊讶,请检查波纹管(计算平方和)。

from functools import reduce
import datetime


def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next**2, numbers, 0)


def square_sum2(numbers):
    a = 0
    for i in numbers:
        i = i**2
        a += i
    return a

def square_sum3(numbers):
    sqrt = lambda x: x**2
    return sum(map(sqrt, numbers))

def square_sum4(numbers):
    return(sum([int(i)**2 for i in numbers]))


time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
0:00:00.302000 #Reduce
0:00:00.144000 #For loop
0:00:00.318000 #Map
0:00:00.390000 #List comprehension

I wrote a simple script that test the speed and this is what I found out. Actually for loop was fastest in my case. That really suprised me, check out bellow (was calculating sum of squares).

from functools import reduce
import datetime


def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next**2, numbers, 0)


def square_sum2(numbers):
    a = 0
    for i in numbers:
        i = i**2
        a += i
    return a

def square_sum3(numbers):
    sqrt = lambda x: x**2
    return sum(map(sqrt, numbers))

def square_sum4(numbers):
    return(sum([int(i)**2 for i in numbers]))


time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
0:00:00.302000 #Reduce
0:00:00.144000 #For loop
0:00:00.318000 #Map
0:00:00.390000 #List comprehension

回答 4

我修改了@Alisa的代码,并用来cProfile说明为什么列表理解速度更快:

from functools import reduce
import datetime

def reduce_(numbers):
    return reduce(lambda sum, next: sum + next * next, numbers, 0)

def for_loop(numbers):
    a = []
    for i in numbers:
        a.append(i*2)
    a = sum(a)
    return a

def map_(numbers):
    sqrt = lambda x: x*x
    return sum(map(sqrt, numbers))

def list_comp(numbers):
    return(sum([i*i for i in numbers]))

funcs = [
        reduce_,
        for_loop,
        map_,
        list_comp
        ]

if __name__ == "__main__":
    # [1, 2, 5, 3, 1, 2, 5, 3]
    import cProfile
    for f in funcs:
        print('=' * 25)
        print("Profiling:", f.__name__)
        print('=' * 25)
        pr = cProfile.Profile()
        for i in range(10**6):
            pr.runcall(f, [1, 2, 5, 3, 1, 2, 5, 3])
        pr.create_stats()
        pr.print_stats()

结果如下:

=========================
Profiling: reduce_
=========================
         11000000 function calls in 1.501 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.162    0.000    1.473    0.000 profiling.py:4(reduce_)
  8000000    0.461    0.000    0.461    0.000 profiling.py:5(<lambda>)
  1000000    0.850    0.000    1.311    0.000 {built-in method _functools.reduce}
  1000000    0.028    0.000    0.028    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: for_loop
=========================
         11000000 function calls in 1.372 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.879    0.000    1.344    0.000 profiling.py:7(for_loop)
  1000000    0.145    0.000    0.145    0.000 {built-in method builtins.sum}
  8000000    0.320    0.000    0.320    0.000 {method 'append' of 'list' objects}
  1000000    0.027    0.000    0.027    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: map_
=========================
         11000000 function calls in 1.470 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.264    0.000    1.442    0.000 profiling.py:14(map_)
  8000000    0.387    0.000    0.387    0.000 profiling.py:15(<lambda>)
  1000000    0.791    0.000    1.178    0.000 {built-in method builtins.sum}
  1000000    0.028    0.000    0.028    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: list_comp
=========================
         4000000 function calls in 0.737 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.318    0.000    0.709    0.000 profiling.py:18(list_comp)
  1000000    0.261    0.000    0.261    0.000 profiling.py:19(<listcomp>)
  1000000    0.131    0.000    0.131    0.000 {built-in method builtins.sum}
  1000000    0.027    0.000    0.027    0.000 {method 'disable' of '_lsprof.Profiler' objects}

恕我直言:

  • reduce并且map总体上来说很慢。不仅如此,summap返回sum列表相比,在返回的迭代器上使用慢
  • for_loop 使用append,这在某种程度上当然很慢
  • 列表理解不仅花费了最少的时间来构建列表,而且与之sum相比,它也变得更快map

I modified @Alisa’s code and used cProfile to show why list comprehension is faster:

from functools import reduce
import datetime

def reduce_(numbers):
    return reduce(lambda sum, next: sum + next * next, numbers, 0)

def for_loop(numbers):
    a = []
    for i in numbers:
        a.append(i*2)
    a = sum(a)
    return a

def map_(numbers):
    sqrt = lambda x: x*x
    return sum(map(sqrt, numbers))

def list_comp(numbers):
    return(sum([i*i for i in numbers]))

funcs = [
        reduce_,
        for_loop,
        map_,
        list_comp
        ]

if __name__ == "__main__":
    # [1, 2, 5, 3, 1, 2, 5, 3]
    import cProfile
    for f in funcs:
        print('=' * 25)
        print("Profiling:", f.__name__)
        print('=' * 25)
        pr = cProfile.Profile()
        for i in range(10**6):
            pr.runcall(f, [1, 2, 5, 3, 1, 2, 5, 3])
        pr.create_stats()
        pr.print_stats()

Here’s the results:

=========================
Profiling: reduce_
=========================
         11000000 function calls in 1.501 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.162    0.000    1.473    0.000 profiling.py:4(reduce_)
  8000000    0.461    0.000    0.461    0.000 profiling.py:5(<lambda>)
  1000000    0.850    0.000    1.311    0.000 {built-in method _functools.reduce}
  1000000    0.028    0.000    0.028    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: for_loop
=========================
         11000000 function calls in 1.372 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.879    0.000    1.344    0.000 profiling.py:7(for_loop)
  1000000    0.145    0.000    0.145    0.000 {built-in method builtins.sum}
  8000000    0.320    0.000    0.320    0.000 {method 'append' of 'list' objects}
  1000000    0.027    0.000    0.027    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: map_
=========================
         11000000 function calls in 1.470 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.264    0.000    1.442    0.000 profiling.py:14(map_)
  8000000    0.387    0.000    0.387    0.000 profiling.py:15(<lambda>)
  1000000    0.791    0.000    1.178    0.000 {built-in method builtins.sum}
  1000000    0.028    0.000    0.028    0.000 {method 'disable' of '_lsprof.Profiler' objects}


=========================
Profiling: list_comp
=========================
         4000000 function calls in 0.737 seconds

   Ordered by: standard name

   ncalls  tottime  percall  cumtime  percall filename:lineno(function)
  1000000    0.318    0.000    0.709    0.000 profiling.py:18(list_comp)
  1000000    0.261    0.000    0.261    0.000 profiling.py:19(<listcomp>)
  1000000    0.131    0.000    0.131    0.000 {built-in method builtins.sum}
  1000000    0.027    0.000    0.027    0.000 {method 'disable' of '_lsprof.Profiler' objects}

IMHO:

  • reduce and map are in general pretty slow. Not only that, using sum on the iterators that map returned is slow, compared to suming a list
  • for_loop uses append, which is of course slow to some extent
  • list-comprehension not only spent the least time building the list, it also makes sum much quicker, in contrast to map

回答 5

Alphii答案增加一点扭曲,实际上for循环将是第二好,并且比循环慢6倍map

from functools import reduce
import datetime


def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next**2, numbers, 0)


def square_sum2(numbers):
    a = 0
    for i in numbers:
        a += i**2
    return a

def square_sum3(numbers):
    a = 0
    map(lambda x: a+x**2, numbers)
    return a

def square_sum4(numbers):
    a = 0
    return [a+i**2 for i in numbers]

time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])

主要的更改是消除了缓慢的sum通话,以及int()在最后一种情况下可能不必要的通话。实际上,将for循环和map放在相同的术语中就可以说是事实。请记住,lambda是功能性概念,从理论上讲不应该具有副作用,但是,它们可以具有诸如添加到的副作用a。在这种情况下使用Python 3.6.1,Ubuntu 14.04,Intel(R)Core(TM)i7-4770 CPU @ 3.40GHz时的结果

0:00:00.257703 #Reduce
0:00:00.184898 #For loop
0:00:00.031718 #Map
0:00:00.212699 #List comprehension

Adding a twist to Alphii answer, actually the for loop would be second best and about 6 times slower than map

from functools import reduce
import datetime


def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next**2, numbers, 0)


def square_sum2(numbers):
    a = 0
    for i in numbers:
        a += i**2
    return a

def square_sum3(numbers):
    a = 0
    map(lambda x: a+x**2, numbers)
    return a

def square_sum4(numbers):
    a = 0
    return [a+i**2 for i in numbers]

time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])

Main changes have been to eliminate the slow sum calls, as well as the probably unnecessary int() in the last case. Putting the for loop and map in the same terms makes it quite fact, actually. Remember that lambdas are functional concepts and theoretically shouldn’t have side effects, but, well, they can have side effects like adding to a. Results in this case with Python 3.6.1, Ubuntu 14.04, Intel(R) Core(TM) i7-4770 CPU @ 3.40GHz

0:00:00.257703 #Reduce
0:00:00.184898 #For loop
0:00:00.031718 #Map
0:00:00.212699 #List comprehension

回答 6

我设法修改了@alpiii的一些代码,并发现List理解比for循环快一点。它可能是由引起的int(),在列表理解和for循环之间是不公平的。

from functools import reduce
import datetime

def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next*next, numbers, 0)

def square_sum2(numbers):
    a = []
    for i in numbers:
        a.append(i*2)
    a = sum(a)
    return a

def square_sum3(numbers):
    sqrt = lambda x: x*x
    return sum(map(sqrt, numbers))

def square_sum4(numbers):
    return(sum([i*i for i in numbers]))

time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
0:00:00.101122 #Reduce

0:00:00.089216 #For loop

0:00:00.101532 #Map

0:00:00.068916 #List comprehension

I have managed to modify some of @alpiii’s code and discovered that List comprehension is a little faster than for loop. It might be caused by int(), it is not fair between list comprehension and for loop.

from functools import reduce
import datetime

def time_it(func, numbers, *args):
    start_t = datetime.datetime.now()
    for i in range(numbers):
        func(args[0])
    print (datetime.datetime.now()-start_t)

def square_sum1(numbers):
    return reduce(lambda sum, next: sum+next*next, numbers, 0)

def square_sum2(numbers):
    a = []
    for i in numbers:
        a.append(i*2)
    a = sum(a)
    return a

def square_sum3(numbers):
    sqrt = lambda x: x*x
    return sum(map(sqrt, numbers))

def square_sum4(numbers):
    return(sum([i*i for i in numbers]))

time_it(square_sum1, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum2, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum3, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
time_it(square_sum4, 100000, [1, 2, 5, 3, 1, 2, 5, 3])
0:00:00.101122 #Reduce

0:00:00.089216 #For loop

0:00:00.101532 #Map

0:00:00.068916 #List comprehension

如何检查列表中的所有元素是否都符合条件?

问题:如何检查列表中的所有元素是否都符合条件?

我有一个包含20000个列表的列表。我将每个列表的第3个元素用作标志。只要至少一个元素的标志为0,我想在此列表上执行一些操作,就像:

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

开始时,所有标志均为0。我使用while循环检查至少一个元素的标志是否为0:

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

如果check(my_list)返回True,那么我将继续处理我的列表:

while check(my_list):
    for item in my_list:
        if condition:
            item[2] = 1
        else:
            do_sth()

实际上,我想在对my_list进行迭代时删除其中的一个元素,但是在对它进行迭代时,不允许删除项目。

原始的my_list没有标志:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]

由于在迭代过程中无法删除元素,因此发明了这些标志。但是,my_list其中包含许多项目,并且while循环在每个for循环中读取所有项目,这会花费大量时间!你有什么建议吗?

I have a list consisting of like 20000 lists. I use each list’s 3rd element as a flag. I want to do some operations on this list as long as at least one element’s flag is 0, it’s like:

my_list = [["a", "b", 0], ["c", "d", 0], ["e", "f", 0], .....]

In the beginning, all flags are 0. I use a while loop to check if at least one element’s flag is 0:

def check(list_):
    for item in list_:
        if item[2] == 0:
            return True
    return False

If check(my_list) returns True, then I continue working on my list:

while check(my_list):
    for item in my_list:
        if condition:
            item[2] = 1
        else:
            do_sth()

Actually, I wanted to remove an element in my_list as I iterated over it, but I’m not allowed to remove items as I iterate over it.

Original my_list didn’t have flags:

my_list = [["a", "b"], ["c", "d"], ["e", "f"], .....]

Since I couldn’t remove elements as I iterated over it, I invented these flags. But the my_list contains many items, and while loop reads all of them at each for loop, and it consumes lots of time! Do you have any suggestions?


回答 0

最好的答案是使用all(),这是这种情况的内置函数。我们将其与生成器表达式结合使用,以干净高效地生成您想要的结果。例如:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

请注意,all(flag == 0 for (_, _, flag) in items)它直接等效于all(item[2] == 0 for item in items),在这种情况下阅读起来要好一些。

并且,对于过滤器示例,使用列表推导(当然,可以在适当的地方使用生成器表达式):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

如果要检查至少一个元素为0,则更好的选择是使用any()更具可读性的元素:

>>> any(flag == 0 for (_, _, flag) in items)
True

The best answer here is to use all(), which is the builtin for this situation. We combine this with a generator expression to produce the result you want cleanly and efficiently. For example:

>>> items = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
True
>>> items = [[1, 2, 0], [1, 2, 1], [1, 2, 0]]
>>> all(flag == 0 for (_, _, flag) in items)
False

Note that all(flag == 0 for (_, _, flag) in items) is directly equivalent to all(item[2] == 0 for item in items), it’s just a little nicer to read in this case.

And, for the filter example, a list comprehension (of course, you could use a generator expression where appropriate):

>>> [x for x in items if x[2] == 0]
[[1, 2, 0], [1, 2, 0]]

If you want to check at least one element is 0, the better option is to use any() which is more readable:

>>> any(flag == 0 for (_, _, flag) in items)
True

回答 1

如果要检查列表中的任何项目是否违反条件,请使用all

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

要删除所有不匹配的元素,请使用 filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

If you want to check if any item in the list violates a condition use all:

if all([x[2] == 0 for x in lista]):
    # Will run if all elements in the list has x[2] = 0 (use not to invert if necessary)

To remove all elements not matching, use filter

# Will remove all elements where x[2] is 0
listb = filter(lambda x: x[2] != 0, listb)

回答 2

您可以像这样使用itertools的takewhile,一旦满足条件会使您的语句失败,它将停止。相反的方法是dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

You could use itertools’s takewhile like this, it will stop once a condition is met that fails your statement. The opposite method would be dropwhile

for x in itertools.takewhile(lambda x: x[2] == 0, list)
    print x

回答 3

另一种使用方式itertools.ifilter。这会检查真实性和过程(使用lambda

样品-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

Another way to use itertools.ifilter. This checks truthiness and process (using lambda)

Sample-

for x in itertools.ifilter(lambda x: x[2] == 0, my_list):
    print x

回答 4

这种方式比使用以下方式更加灵活all()

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

或更简洁地:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

this way is a bit more flexible than using all():

my_list = [[1, 2, 0], [1, 2, 0], [1, 2, 0]]
all_zeros = False if False in [x[2] == 0 for x in my_list] else True
any_zeros = True if True in [x[2] == 0 for x in my_list] else False

or more succinctly:

all_zeros = not False in [x[2] == 0 for x in my_list]
any_zeros = 0 in [x[2] for x in my_list]

我如何理解Python循环的`else`子句?

问题:我如何理解Python循环的`else`子句?

许多Python程序员可能没有意识到while循环和for循环的语法包含一个可选else:子句:

for val in iterable:
    do_something(val)
else:
    clean_up()

else子句的主体是执行某些类型的清理操作的好地方,并在循环的正常终止时执行:即,使用returnbreak跳过else子句退出循环;continue执行后退出。我知道这只是因为我只是看着它(再次),因为我永远记得else子句被执行。

总是?顾名思义,在循环的“失败”上?定期终止吗?即使循环退出return?我永远不能完全确定,不查它。

我将不确定性归咎于关键字的选择:我发现else这种语义难以置信。我的问题不是“为什么要为此目的使用该关键字”(虽然只有在阅读了答案和评论之后,我才可能会投票关闭关键字),但我如何考虑该else关键字,以便其语义有意义,我因此可以记住吗?

我敢肯定,对此进行了大量讨论,并且我可以想象做出这一选择是为了与try语句的else:子句(我也必须查找)保持一致,并且其目标是不添加到该语句的列表中。 Python的保留字。也许选择的原因else将阐明其功能并使之更加令人难忘,但我是将名称与功能联系在一起,而不是出于历史解释本身。

这个问题的答案(我的问题作为与之重复的问题简短地结束了)包含很多有趣的背景故事。我的问题有不同的侧重点(如何将特定语义else与关键字选择联系起来),但是我觉得应该在某个地方链接到该问题。

Many Python programmers are probably unaware that the syntax of while loops and for loops includes an optional else: clause:

for val in iterable:
    do_something(val)
else:
    clean_up()

The body of the else clause is a good place for certain kinds of clean-up actions, and is executed on normal termination of the loop: I.e., exiting the loop with return or break skips the else clause; exiting after a continue executes it. I know this only because I just looked it up (yet again), because I can never remember when the else clause is executed.

Always? On “failure” of the loop, as the name suggests? On regular termination? Even if the loop is exited with return? I can never be entirely sure without looking it up.

I blame my persisting uncertainty on the choice of keyword: I find else incredibly unmnemonic for this semantics. My question is not “why is this keyword used for this purpose” (which I would probably vote to close, though only after reading the answers and comments), but how can I think about the else keyword so that its semantics make sense, and I can therefore remember it?

I’m sure there was a fair amount of discussion about this, and I can imagine that the choice was made for consistency with the try statement’s else: clause (which I also have to look up), and with the goal of not adding to the list of Python’s reserved words. Perhaps the reasons for choosing else will clarify its function and make it more memorable, but I’m after connecting name to function, not after historical explanation per se.

The answers to this question, which my question was briefly closed as a duplicate of, contain a lot of interesting back story. My question has a different focus (how to connect the specific semantics of else with the keyword choice), but I feel there should be a link to this question somewhere.


回答 0

(这受@Mark Tolonen的回答启发。)

一个if语句运行它else,如果它的条件计算为false条款。同样,while如果条件的条件评估为false ,则循环将运行else子句。

此规则与您描述的行为匹配:

  • 在正常执行中,while循环会重复运行直到条件评估为false为止,因此自然退出循环将运行else子句。
  • 当执行一条break语句时,您退出循环而不评估条件,因此条件不能评估为false,并且您从不运行else子句。
  • 当您执行一条continue语句时,您将再次评估条件,并按照循环迭代开始时的正常方式进行操作。因此,如果条件为true,则继续循环,但是如果条件为false,则运行else子句。
  • 其他退出循环的方法(例如)return不会评估条件,因此不会运行else子句。

for循环的行为方式相同。如果迭代器具有更多元素,则仅将条件视为true,否则将其视为false。

(This is inspired by @Mark Tolonen’s answer.)

An if statement runs its else clause if its condition evaluates to false. Identically, a while loop runs the else clause if its condition evaluates to false.

This rule matches the behavior you described:

  • In normal execution, the while loop repeatedly runs until the condition evaluates to false, and therefore naturally exiting the loop runs the else clause.
  • When you execute a break statement, you exit out of the loop without evaluating the condition, so the condition cannot evaluate to false and you never run the else clause.
  • When you execute a continue statement, you evaluate the condition again, and do exactly what you normally would at the beginning of a loop iteration. So, if the condition is true, you keep looping, but if it is false you run the else clause.
  • Other methods of exiting the loop, such as return, do not evaluate the condition and therefore do not run the else clause.

for loops behave the same way. Just consider the condition as true if the iterator has more elements, or false otherwise.


回答 1

最好这样考虑:如果前一个块中的所有内容都正确,以至于用尽,else始终执行该块。for

在这种情况下,正确意味着不exception,不break,不return。劫持控件的任何语句for都将导致该else块被绕过。


在中搜索商品时,找到了一个常见的用例iterable,当找到该商品或"not found"通过以下else块引发/打印一个标志时,将针对该商品取消搜索:

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

A continue不会从中劫持控制权for,因此控制权将elsefor用尽后继续进行。

Better to think of it this way: The else block will always be executed if everything goes right in the preceding for block such that it reaches exhaustion.

Right in this context will mean no exception, no break, no return. Any statement that hijacks control from for will cause the else block to be bypassed.


A common use case is found when searching for an item in an iterable, for which the search is either called off when the item is found or a "not found" flag is raised/printed via the following else block:

for items in basket:
    if isinstance(item, Egg):
        break
else:
    print("No eggs in basket")  

A continue does not hijack control from for, so control will proceed to the else after the for is exhausted.


回答 2

什么时候if执行else?当其条件为假时。正是在相同while/ else。因此,您可以将while/ else视为if一直运行其真实条件直到其评估为false的。A break不会改变这一点。它只是跳出包含循环而没有评估。该else如果仅执行评估if/ while条件为假。

for是相似的,除了它的假条件被消耗其迭代器。

continue并且break不要执行else。那不是他们的功能。在break退出循环含有。将continue返回到循环包含,其中,所述循环条件被评估的顶部。评估if/ while将错误(或for没有更多项目)执行的动作是else没有其他方法的。

When does an if execute an else? When its condition is false. It is exactly the same for the while/else. So you can think of while/else as just an if that keeps running its true condition until it evaluates false. A break doesn’t change that. It just jumps out of the containing loop with no evaluation. The else is only executed if evaluating the if/while condition is false.

The for is similar, except its false condition is exhausting its iterator.

continue and break don’t execute else. That isn’t their function. The break exits the containing loop. The continue goes back to the top of the containing loop, where the loop condition is evaluated. It is the act of evaluating if/while to false (or for has no more items) that executes else and no other way.


回答 3

这实际上是什么意思:

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

这是编写这种常见模式的一种更好的方式:

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

else如果有一个return原因,那么该子句将不会执行return,这意味着它会这样做。您可能想到的唯一exceptions是finally,其目的是确保始终执行该exceptions。

continue与这件事没有什么特别的关系。它导致循环的当前迭代结束,而这可能恰好结束了整个循环,显然,在这种情况下,循环并未以结束break

try/else 很相似:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

This is what it essentially means:

for/while ...:
    if ...:
        break
if there was a break:
    pass
else:
    ...

It’s a nicer way of writing of this common pattern:

found = False
for/while ...:
    if ...:
        found = True
        break
if not found:
    ...

The else clause will not be executed if there is a return because return leaves the function, as it is meant to. The only exception to that which you may be thinking of is finally, whose purpose is to be sure that it is always executed.

continue has nothing special to do with this matter. It causes the current iteration of the loop to end which may happen to end the entire loop, and clearly in that case the loop wasn’t ended by a break.

try/else is similar:

try:
    ...
except:
    ...
if there was an exception:
    pass
else:
    ...

回答 4

如果您将循环视为与此类似的结构(某种伪代码):

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

这可能更有意义。循环本质上只是if重复一个语句,直到条件为为止false。这是重要的一点。循环检查其条件并查看是否为false,因此执行else(就像正常if/else),然后完成循环。

因此请注意,else 检查条件后,将执行唯一的获取。这意味着,如果在执行过程中使用a return或a 退出循环的主体break,因为不会再次检查条件,else则不会执行大小写。

continue另一方面,A 停止当前执行,然后跳回以再次检查循环条件,这就是else在这种情况下可以达到的原因。

If you think of your loops as a structure similar to this (somewhat pseudo-code):

loop:
if condition then

   ... //execute body
   goto loop
else
   ...

it might make a little bit more sense. A loop is essentially just an if statement that is repeated until the condition is false. And this is the important point. The loop checks its condition and sees that it’s false, thus executes the else (just like a normal if/else) and then the loop is done.

So notice that the else only get’s executed when the condition is checked. That means that if you exit the body of the loop in the middle of execution with for example a return or a break, since the condition is not checked again, the else case won’t be executed.

A continue on the other hand stops the current execution and then jumps back to check the condition of the loop again, which is why the else can be reached in this scenario.


回答 5

我对循环的else子句的了解是在我观看Raymond Hettinger的演讲时,他讲了一个有关他认为应该如何称呼它的故事nobreak。看下面的代码,您认为它将做什么?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

您会怎么做?好吧,nobreak只有在break语句未在循环中命中的情况下,才会执行所说的部分。

My gotcha moment with the loop’s else clause was when I was watching a talk by Raymond Hettinger, who told a story about how he thought it should have been called nobreak. Take a look at the following code, what do you think it would do?

for i in range(10):
    if test(i):
        break
    # ... work with i
nobreak:
    print('Loop completed')

What would you guess it does? Well, the part that says nobreak would only be executed if a break statement wasn’t hit in the loop.


回答 6

通常,我倾向于想到这样的循环结构:

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

非常像可变数量的if/elif语句:

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

在这种情况下,elsefor循环上的语句的工作原理elseelifs 链上的语句完全相同,仅在条件为True之前没有条件时才执行。(或者用return异常中断执行)如果我的循环通常不符合此规范,则出于for: else您发布此问题的确切原因,我选择不使用:这是不直观的。

Usually I tend to think of a loop structure like this:

for item in my_sequence:
    if logic(item):
        do_something(item)
        break

To be a lot like a variable number of if/elif statements:

if logic(my_seq[0]):
    do_something(my_seq[0])
elif logic(my_seq[1]):
    do_something(my_seq[1])
elif logic(my_seq[2]):
    do_something(my_seq[2])
....
elif logic(my_seq[-1]):
    do_something(my_seq[-1])

In this case the else statement on the for loop works exactly like the else statement on the chain of elifs, it only executes if none of the conditions before it evaluate to True. (or break execution with return or an exception) If my loop does not fit this specification usually I choose to opt out of using for: else for the exact reason you posted this question: it is non-intuitive.


回答 7

其他人已经解释了的机制while/for...else,并且Python 3语言参考具有权威性的定义(请参见whilefor),但这是我的个人助记符FWIW。我想对我来说关键在于将其分解为两部分:一个部分用于理解else与循环条件相关的的含义,另一部分用于理解循环控制。

我发现从理解开始是最容易的while...else

while你有更多物品,做东西,else如果用完了,这样做

for...else助记符是基本相同的:

for每个项目,做一些事情,但是else如果用完了,请这样做

在这两种情况下,else仅在没有更多要处理的项目并且以常规方式(即,否breakreturn)处理了最后一个项目时才到达该零件。一个continue刚刚回到如果有任何更多的项目看。这些规则的助记符适用于whilefor

break荷兰国际集团或returnING,没有什么是else做的,
当我说continue,这是“环回至开始”为您服务

–显然,“循环返回开始”的意思是循环的开始,在该循环中,我们检查可迭代项中是否还有其他项,else就而言,它continue实际上根本没有作用。

Others have already explained the mechanics of while/for...else, and the Python 3 language reference has the authoritative definition (see while and for), but here is my personal mnemonic, FWIW. I guess the key for me has been to break this down into two parts: one for understanding the meaning of the else in relation to the loop conditional, and one for understanding loop control.

I find it’s easiest to start by understanding while...else:

while you have more items, do stuff, else if you run out, do this

The for...else mnemonic is basically the same:

for every item, do stuff, but else if you run out, do this

In both cases, the else part is only reached once there are no more items to process, and the last item has been processed in a regular manner (i.e. no break or return). A continue just goes back and sees if there are any more items. My mnemonic for these rules applies to both while and for:

when breaking or returning, there’s nothing else to do,
and when I say continue, that’s “loop back to start” for you

– with “loop back to start” meaning, obviously, the start of the loop where we check whether there are any more items in the iterable, so as far as the else is concerned, continue really plays no role at all.


回答 8

测试驱动的开发(TDD)中,当使用转换优先级前提范式时,您将循环视为条件语句的概括。

如果仅考虑简单的if/else(no elif)语句,则此方法可以与以下语法很好地结合:

if cond:
    # 1
else:
    # 2

概括为:

while cond:  # <-- generalization
    # 1
else:
    # 2

很好

用其他语言,TDD从单个案例到具有集合案例的步骤需要更多的重构。


这是8thlight博客的示例:

在8thlight博客的链接文章中,考虑了自动换行kata:在字符串(s下面的片段中的变量)上添加换行符以使其适合给定的宽度(length下面的片段中的变量)。一方面,实现看起来如下(Java):

String result = "";
if (s.length() > length) {
    result = s.substring(0, length) + "\n" + s.substring(length);
} else {
    result = s;
}
return result;

下一个当前失败的测试是:

@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
    assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
    }

因此,我们有条件运行的代码:当满足特定条件时,将添加一个换行符。我们想要改进代码以处理多个换行符。本文中提出的解决方案建议应用(if-> while)转换,但是作者评论说:

虽然循环不能包含else子句,所以我们需要else通过减少路径来消除if路径。同样,这是重构。

在一次失败的测试中,这迫使对代码进行更多更改:

String result = "";
while (s.length() > length) {
    result += s.substring(0, length) + "\n";
    s = s.substring(length);
}
result += s;

在TDD中,我们希望编写尽可能少的代码以使测试通过。借助Python的语法,可以进行以下转换:

从:

result = ""
if len(s) > length:
    result = s[0:length] + "\n"
    s = s[length:]
else:
    result += s

至:

result = ""
while len(s) > length:
    result += s[0:length] + "\n"
    s = s[length:]
else:
    result += s

In Test-driven development (TDD), when using the Transformation Priority Premise paradigm, you treat loops as a generalization of conditional statements.

This approach combines well with this syntax, if you consider only simple if/else (no elif) statements:

if cond:
    # 1
else:
    # 2

generalizes to:

while cond:  # <-- generalization
    # 1
else:
    # 2

nicely.

In other languages, TDD steps from a single case to cases with collections require more refactoring.


Here is an example from 8thlight blog:

In the linked article at 8thlight blog, the Word Wrap kata is considered: adding line breaks to strings (the s variable in the snippets below) to make them fit a given width (the length variable in the snippets below). At one point the implementation looks as follows (Java):

String result = "";
if (s.length() > length) {
    result = s.substring(0, length) + "\n" + s.substring(length);
} else {
    result = s;
}
return result;

and the next test, that currently fails is:

@Test
public void WordLongerThanTwiceLengthShouldBreakTwice() throws Exception {
    assertThat(wrap("verylongword", 4), is("very\nlong\nword"));
    }

So we have code that works conditionally: when a particular condition is met, a line break is added. We want to improve the code to handle multiple line breaks. The solution presented in the article proposes to apply the (if->while) transformation, however the author makes a comment that:

While loops can’t have else clauses, so we need to eliminate the else path by doing less in the if path. Again, this is a refactoring.

which forces to do more changes to the code in the context of one failing test:

String result = "";
while (s.length() > length) {
    result += s.substring(0, length) + "\n";
    s = s.substring(length);
}
result += s;

In TDD we want to write as less code as possible to make tests pass. Thanks to Python’s syntax the following transformation is possible:

from:

result = ""
if len(s) > length:
    result = s[0:length] + "\n"
    s = s[length:]
else:
    result += s

to:

result = ""
while len(s) > length:
    result += s[0:length] + "\n"
    s = s[length:]
else:
    result += s

回答 9

else:当您遍历循环结束时,就会触发我的观察方式。

如果你break或者return或者raise你没有过去的迭代循环的结尾,你停下immeadiately,因而else:块将不会运行。如果您continue仍然循环结束,因为continue会跳到下一个迭代。它不会停止循环。

The way I see it, else: fires when you iterate past the end of the loop.

If you break or return or raise you don’t iterate past the end of loop, you stop immeadiately, and thus the else: block won’t run. If you continue you still iterate past the end of loop, since continue just skips to the next iteration. It doesn’t stop the loop.


回答 10

else子句视为循环构造的一部分;break完全脱离循环构造,从而跳过该else子句。

但实际上,我的思维导图只是它是模式C / C ++模式的“结构化”版本:

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

因此,当我for...else自己遇到或编写它时,而不是直接了解它,我会在思维上将其转化为对模式的上述理解,然后确定python语法的哪些部分映射到模式的哪些部分。

(我将“结构化”用惊吓语括起来,因为区别不在于代码是结构化的还是非结构化的,而仅仅是是否有专门针对特定结构的关键字和语法)

Think of the else clause as being part of the loop construct; break breaks out of the loop construct entirely, and thus skips the else clause.

But really, my mental mapping is simply that it’s the ‘structured’ version of the pattern C/C++ pattern:

  for (...) {
    ...
    if (test) { goto done; }
    ...
  }
  ...
done:
  ...

So when I encounter for...else or write it myself, rather than understand it directly, I mentally translate it into the above understanding of the pattern and then work out which parts of the python syntax map to which parts of the pattern.

(I put ‘structured’ in scare quotes because the difference is not whether the code is structured or unstructured, but merely whether there are keywords and grammar dedicated to the particular structure)


回答 11

如果else与配对for,可能会造成混淆。我认为关键字不是else此语法的理想选择,但如果elseifcontains 配对,则break可以看到它确实有意义。else如果没有前面的if语句,则几乎没有用,我相信这就是语法设计者选择关键字的原因。

让我用人类语言来演示它。

for犯罪嫌疑if人组中的每个人都是犯罪分子 break进行调查。else报告失败。

If you pair else with for, it could be confusing. I don’t think the keyword else was a great choice for this syntax, but if you pair else with if which contains break, you can see it actually makes sense. else is barely useful if there is no preceding if statement and I believe this is why the syntax designer chose the keyword.

Let me demonstrate it in human language.

for each person in a group of suspects if anyone is the criminal break the investigation. else report failure.


回答 12

我的思考方式,关键是要考虑continue而不是的含义else

您提到的其他关键字会跳出循环(异常退出),而continue不会跳出循环,只会跳过循环内代码块的其余部分。它可以在循环终止之前发生的事实是偶然的:终止实际上是通过评估循环条件表达式以正常方式完成的。

然后,您只需要记住该else子句是在正常循环终止后执行的。

The way I think about it, the key is to consider the meaning of continue rather than else.

The other keywords you mention break out of the loop (exit abnormally) whilst continue does not, it just skips the remainder of the code block inside the loop. The fact that it can precede loop termination is incidental: the termination is actually done in the normal way by evaluation of the loop conditional expression.

Then you just need to remember that the else clause is executed after normal loop termination.


回答 13

# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''
# tested in Python 3.6.4
def buy_fruit(fruits):
    '''I translate the 'else' below into 'if no break' from for loop '''
    for fruit in fruits:
        if 'rotten' in fruit:
            print(f'do not want to buy {fruit}')
            break
    else:  #if no break
        print(f'ready to buy {fruits}')


if __name__ == '__main__':
    a_bag_of_apples = ['golden delicious', 'honeycrisp', 'rotten mcintosh']
    b_bag_of_apples = ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
    buy_fruit(a_bag_of_apples)
    buy_fruit(b_bag_of_apples)

'''
do not want to buy rotten mcintosh
ready to buy ['granny smith', 'red delicious', 'honeycrisp', 'gala', 'fuji']
'''

在“ for”循环中检测最后一个元素的pythonic方法是什么?

问题:在“ for”循环中检测最后一个元素的pythonic方法是什么?

我想知道对for循环中的最后一个元素进行特殊处理的最佳方法(更紧凑和“ pythonic”的方法)。有一段代码仅应元素之间调用,而在最后一个元素中将被隐藏。

这是我目前的操作方式:

for i, data in enumerate(data_list):
    code_that_is_done_for_every_element
    if i != len(data_list) - 1:
        code_that_is_done_between_elements

有什么更好的办法吗?

注意:我不希望使用hack之类的东西reduce;)

I’d like to know the best way (more compact and “pythonic” way) to do a special treatment for the last element in a for loop. There is a piece of code that should be called only between elements, being suppressed in the last one.

Here is how I currently do it:

for i, data in enumerate(data_list):
    code_that_is_done_for_every_element
    if i != len(data_list) - 1:
        code_that_is_done_between_elements

Is there any better way?

Note: I don’t want to make it with hacks such as using reduce. ;)


回答 0

在大多数情况下,使第一个迭代成为特殊情况而不是最后一个案例更容易(且更便宜):

first = True
for data in data_list:
    if first:
        first = False
    else:
        between_items()

    item()

这将适用于任何可迭代的对象,即使对于那些没有len()

file = open('/path/to/file')
for line in file:
    process_line(line)

    # No way of telling if this is the last line!

除此之外,我认为没有通用的更好的解决方案,因为这取决于您要执行的操作。例如,如果要从列表中构建字符串,则使用自然str.join()要比使用for“特殊情况”循环更好。


使用相同的原理,但更紧凑:

for i, line in enumerate(data_list):
    if i > 0:
        between_items()
    item()

看起来很熟悉,不是吗?:)


对于@ofko以及其他确实需要确定iterable的当前值是否len()是最后一个值的人,您需要向前看:

def lookahead(iterable):
    """Pass through all values from the given iterable, augmented by the
    information if there are more values to come after the current one
    (True), or if it is the last value (False).
    """
    # Get an iterator and pull the first value.
    it = iter(iterable)
    last = next(it)
    # Run the iterator to exhaustion (starting from the second value).
    for val in it:
        # Report the *previous* value (more to come).
        yield last, True
        last = val
    # Report the last value.
    yield last, False

然后,您可以像这样使用它:

>>> for i, has_more in lookahead(range(3)):
...     print(i, has_more)
0 True
1 True
2 False

Most of the times it is easier (and cheaper) to make the first iteration the special case instead of the last one:

first = True
for data in data_list:
    if first:
        first = False
    else:
        between_items()

    item()

This will work for any iterable, even for those that have no len():

file = open('/path/to/file')
for line in file:
    process_line(line)

    # No way of telling if this is the last line!

Apart from that, I don’t think there is a generally superior solution as it depends on what you are trying to do. For example, if you are building a string from a list, it’s naturally better to use str.join() than using a for loop “with special case”.


Using the same principle but more compact:

for i, line in enumerate(data_list):
    if i > 0:
        between_items()
    item()

Looks familiar, doesn’t it? :)


For @ofko, and others who really need to find out if the current value of an iterable without len() is the last one, you will need to look ahead:

def lookahead(iterable):
    """Pass through all values from the given iterable, augmented by the
    information if there are more values to come after the current one
    (True), or if it is the last value (False).
    """
    # Get an iterator and pull the first value.
    it = iter(iterable)
    last = next(it)
    # Run the iterator to exhaustion (starting from the second value).
    for val in it:
        # Report the *previous* value (more to come).
        yield last, True
        last = val
    # Report the last value.
    yield last, False

Then you can use it like this:

>>> for i, has_more in lookahead(range(3)):
...     print(i, has_more)
0 True
1 True
2 False

回答 1

尽管这个问题已经很老了,但我还是通过Google来到这里的,我发现了一种非常简单的方法:列表切片。假设您要在所有列表条目之间添加“&”。

s = ""
l = [1, 2, 3]
for i in l[:-1]:
    s = s + str(i) + ' & '
s = s + str(l[-1])

这将返回“ 1&2&3”。

Although that question is pretty old, I came here via google and I found a quite simple way: List slicing. Let’s say you want to put an ‘&’ between all list entries.

s = ""
l = [1, 2, 3]
for i in l[:-1]:
    s = s + str(i) + ' & '
s = s + str(l[-1])

This returns ‘1 & 2 & 3’.


回答 2

“之间的代码”是头尾模式的一个示例。

您有一个项目,其后是一系列(在项目之间)对。您也可以将其视为(项目之间)对的序列,后跟一个项目。通常,将第一个元素作为特殊条件,而将所有其他元素作为“标准”条件,则更为简单。

此外,为避免重复代码,您必须提供一个函数或其他对象来包含您不想重复的代码。将if语句嵌入到一个循环中,该循环始终为假(一次除外),这有点愚蠢。

def item_processing( item ):
    # *the common processing*

head_tail_iter = iter( someSequence )
head = head_tail_iter.next()
item_processing( head )
for item in head_tail_iter:
    # *the between processing*
    item_processing( item )

这是更可靠的,因为它更容易证明,它不会创建额外的数据结构(即列表的副本),也不需要浪费很多执行if条件,而if条件总是一次,除非一次。

The ‘code between’ is an example of the Head-Tail pattern.

You have an item, which is followed by a sequence of ( between, item ) pairs. You can also view this as a sequence of (item, between) pairs followed by an item. It’s generally simpler to take the first element as special and all the others as the “standard” case.

Further, to avoid repeating code, you have to provide a function or other object to contain the code you don’t want to repeat. Embedding an if statement in a loop which is always false except one time is kind of silly.

def item_processing( item ):
    # *the common processing*

head_tail_iter = iter( someSequence )
head = next(head_tail_iter)
item_processing( head )
for item in head_tail_iter:
    # *the between processing*
    item_processing( item )

This is more reliable because it’s slightly easier to prove, It doesn’t create an extra data structure (i.e., a copy of a list) and doesn’t require a lot of wasted execution of an if condition which is always false except once.


回答 3

如果您只是想修改其中的最后一个元素,data_list则可以使用表示法:

L[-1]

但是,您似乎要做的还不止这些。您的方式并没有错。我什至快速浏览了一些Django代码的模板标签,它们基本上完成了您正在做的事情。

If you’re simply looking to modify the last element in data_list then you can simply use the notation:

L[-1]

However, it looks like you’re doing more than that. There is nothing really wrong with your way. I even took a quick glance at some Django code for their template tags and they do basically what you’re doing.


回答 4

如果项目是唯一的:

for x in list:
    #code
    if x == list[-1]:
        #code

其他选择:

pos = -1
for x in list:
    pos += 1
    #code
    if pos == len(list) - 1:
        #code


for x in list:
    #code
#code - e.g. print x


if len(list) > 0:
    for x in list[:-1]
        #code
    for x in list[-1]:
        #code

if the items are unique:

for x in list:
    #code
    if x == list[-1]:
        #code

other options:

pos = -1
for x in list:
    pos += 1
    #code
    if pos == len(list) - 1:
        #code


for x in list:
    #code
#code - e.g. print x


if len(list) > 0:
    for x in list[:-1]
        #code
    for x in list[-1]:
        #code

回答 5

这类似于Ants Aasma的方法,但不使用itertools模块。这也是一个滞后的迭代器,它在迭代器流中先看一个元素:

def last_iter(it):
    # Ensure it's an iterator and get the first field
    it = iter(it)
    prev = next(it)
    for item in it:
        # Lag by one item so I know I'm not at the end
        yield 0, prev
        prev = item
    # Last item
    yield 1, prev

def test(data):
    result = list(last_iter(data))
    if not result:
        return
    if len(result) > 1:
        assert set(x[0] for x in result[:-1]) == set([0]), result
    assert result[-1][0] == 1

test([])
test([1])
test([1, 2])
test(range(5))
test(xrange(4))

for is_last, item in last_iter("Hi!"):
    print is_last, item

This is similar to Ants Aasma’s approach but without using the itertools module. It’s also a lagging iterator which looks-ahead a single element in the iterator stream:

def last_iter(it):
    # Ensure it's an iterator and get the first field
    it = iter(it)
    prev = next(it)
    for item in it:
        # Lag by one item so I know I'm not at the end
        yield 0, prev
        prev = item
    # Last item
    yield 1, prev

def test(data):
    result = list(last_iter(data))
    if not result:
        return
    if len(result) > 1:
        assert set(x[0] for x in result[:-1]) == set([0]), result
    assert result[-1][0] == 1

test([])
test([1])
test([1, 2])
test(range(5))
test(xrange(4))

for is_last, item in last_iter("Hi!"):
    print is_last, item

回答 6

您可以在输入数据上使用滑动窗口来窥视下一个值,并使用哨兵来检测上一个值。这适用于任何可迭代的项目,因此您无需事先知道长度。成对实现来自itertools配方

from itertools import tee, izip, chain

def pairwise(seq):
    a,b = tee(seq)
    next(b, None)
    return izip(a,b)

def annotated_last(seq):
    """Returns an iterable of pairs of input item and a boolean that show if
    the current item is the last item in the sequence."""
    MISSING = object()
    for current_item, next_item in pairwise(chain(seq, [MISSING])):
        yield current_item, next_item is MISSING:

for item, is_last_item in annotated_last(data_list):
    if is_last_item:
        # current item is the last item

You can use a sliding window over the input data to get a peek at the next value and use a sentinel to detect the last value. This works on any iterable, so you don’t need to know the length beforehand. The pairwise implementation is from itertools recipes.

from itertools import tee, izip, chain

def pairwise(seq):
    a,b = tee(seq)
    next(b, None)
    return izip(a,b)

def annotated_last(seq):
    """Returns an iterable of pairs of input item and a boolean that show if
    the current item is the last item in the sequence."""
    MISSING = object()
    for current_item, next_item in pairwise(chain(seq, [MISSING])):
        yield current_item, next_item is MISSING:

for item, is_last_item in annotated_last(data_list):
    if is_last_item:
        # current item is the last item

回答 7

除了最后一个元素之外,是否没有可能遍历所有元素,并在循环之外处理最后一个元素?毕竟,创建了一个循环来执行与您循环的所有元素相似的操作;如果一个元素需要一些特殊的东西,它就不应该出现在循环中。

(另请参见此问题:循环中的最后一个元素是否值得单独处理

编辑:由于问题更多地是关于“之间”,所以第一个元素是特殊的,因为它没有前任,或者最后一个元素是特殊的,因为它没有后继。

Is there no possibility to iterate over all-but the last element, and treat the last one outside of the loop? After all, a loop is created to do something similar to all elements you loop over; if one element needs something special, it shouldn’t be in the loop.

(see also this question: does-the-last-element-in-a-loop-deserve-a-separate-treatment)

EDIT: since the question is more about the “in between”, either the first element is the special one in that it has no predecessor, or the last element is special in that it has no successor.


回答 8

我喜欢@ ethan-t的方法,但是while True从我的角度来看很危险。

data_list = [1, 2, 3, 2, 1]  # sample data
L = list(data_list)  # destroy L instead of data_list
while L:
    e = L.pop(0)
    if L:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')
del L

在这里,data_list使得最后一个元素在值上等于列表中的第一个。L可以交换,data_list但在这种情况下,循环后结果为空。while True如果您在处理之前检查列表是否为空或不需要检查,也可以使用(检查!)。

data_list = [1, 2, 3, 2, 1]
if data_list:
    while True:
        e = data_list.pop(0)
        if data_list:
            print(f'process element {e}')
        else:
            print(f'process last element {e}')
            break
else:
    print('list is empty')

好的方面是它很快。坏-它是可破坏的(data_list变空)。

最直观的解决方案:

data_list = [1, 2, 3, 2, 1]  # sample data
for i, e in enumerate(data_list):
    if i != len(data_list) - 1:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')

哦,是的,您已经提出了!

I like the approach of @ethan-t, but while True is dangerous from my point of view.

data_list = [1, 2, 3, 2, 1]  # sample data
L = list(data_list)  # destroy L instead of data_list
while L:
    e = L.pop(0)
    if L:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')
del L

Here, data_list is so that last element is equal by value to the first one of the list. L can be exchanged with data_list but in this case it results empty after the loop. while True is also possible to use if you check that list is not empty before the processing or the check is not needed (ouch!).

data_list = [1, 2, 3, 2, 1]
if data_list:
    while True:
        e = data_list.pop(0)
        if data_list:
            print(f'process element {e}')
        else:
            print(f'process last element {e}')
            break
else:
    print('list is empty')

The good part is that it is fast. The bad – it is destructible (data_list becomes empty).

Most intuitive solution:

data_list = [1, 2, 3, 2, 1]  # sample data
for i, e in enumerate(data_list):
    if i != len(data_list) - 1:
        print(f'process element {e}')
    else:
        print(f'process last element {e}')

Oh yes, you have already proposed it!


回答 9

您的方式没有错,除非您将有100 000个循环并要保存100 000个“ if”语句。在这种情况下,您可以这样:

iterable = [1,2,3] # Your date
iterator = iter(iterable) # get the data iterator

try :   # wrap all in a try / except
    while 1 : 
        item = iterator.next() 
        print item # put the "for loop" code here
except StopIteration, e : # make the process on the last element here
    print item

输出:

1
2
3
3

但实际上,就您而言,我觉得这太过分了。

无论如何,切片可能会让您更幸运:

for item in iterable[:-1] :
    print item
print "last :", iterable[-1]

#outputs
1
2
last : 3

要不就 :

for item in iterable :
    print item
print iterable[-1]

#outputs
1
2
3
last : 3

最终,采用KISS方式为您做事,这将适用于任何可迭代的事物,包括那些没有__len__

item = ''
for item in iterable :
    print item
print item

1
2
3
3

如果觉得我会那样做,对我来说似乎很简单。

There is nothing wrong with your way, unless you will have 100 000 loops and wants save 100 000 “if” statements. In that case, you can go that way :

iterable = [1,2,3] # Your date
iterator = iter(iterable) # get the data iterator

try :   # wrap all in a try / except
    while 1 : 
        item = iterator.next() 
        print item # put the "for loop" code here
except StopIteration, e : # make the process on the last element here
    print item

Outputs :

1
2
3
3

But really, in your case I feel like it’s overkill.

In any case, you will probably be luckier with slicing :

for item in iterable[:-1] :
    print item
print "last :", iterable[-1]

#outputs
1
2
last : 3

or just :

for item in iterable :
    print item
print iterable[-1]

#outputs
1
2
3
last : 3

Eventually, a KISS way to do you stuff, and that would work with any iterable, including the ones without __len__ :

item = ''
for item in iterable :
    print item
print item

Ouputs:

1
2
3
3

If feel like I would do it that way, seems simple to me.


回答 10

使用切片和is检查最后一个元素:

for data in data_list:
    <code_that_is_done_for_every_element>
    if not data is data_list[-1]:
        <code_that_is_done_between_elements>

注意:仅当列表中的所有元素实际上都不同(在内存中具有不同的位置)时,此方法才有效。在后台,Python可能会检测到相等的元素,并为它们重用相同的对象。例如,对于具有相同值和共同整数的字符串。

Use slicing and is to check for the last element:

for data in data_list:
    <code_that_is_done_for_every_element>
    if not data is data_list[-1]:
        <code_that_is_done_between_elements>

Caveat emptor: This only works if all elements in the list are actually different (have different locations in memory). Under the hood, Python may detect equal elements and reuse the same objects for them. For instance, for strings of the same value and common integers.


回答 11

如果您要查看清单,对我来说,这也可行:

for j in range(0, len(Array)):
    if len(Array) - j > 1:
        notLast()

if you are going through the list, for me this worked too:

for j in range(0, len(Array)):
    if len(Array) - j > 1:
        notLast()

回答 12

Google将我带到这个老问题,我想我可以为这个问题添加另一种方法。

这里的大多数答案将按要求处理for循环控制,但是,如果data_list是可破坏的,我建议您从列表中弹出项目,直到最终得到一个空列表:

while True:
    element = element_list.pop(0)
    do_this_for_all_elements()
    if not element:
        do_this_only_for_last_element()
        break
    do_this_for_all_elements_but_last()

如果您不需要对最后一个元素做任何事情,甚至可以在len(element_list)时使用。我发现此解决方案比next()更优雅。

Google brought me to this old question and I think I could add a different approach to this problem.

Most of the answers here would deal with a proper treatment of a for loop control as it was asked, but if the data_list is destructible, I would suggest that you pop the items from the list until you end up with an empty list:

while True:
    element = element_list.pop(0)
    do_this_for_all_elements()
    if not element:
        do_this_only_for_last_element()
        break
    do_this_for_all_elements_but_last()

you could even use while len(element_list) if you don’t need to do anything with the last element. I find this solution more elegant then dealing with next().


回答 13

对我而言,处理列表结尾处的特殊情况的最简单,最Python的方法是:

for data in data_list[:-1]:
    handle_element(data)
handle_special_element(data_list[-1])

当然,这也可以用来以特殊方式处理第一个元素。

For me the most simple and pythonic way to handle a special case at the end of a list is:

for data in data_list[:-1]:
    handle_element(data)
handle_special_element(data_list[-1])

Of course this can also be used to treat the first element in a special way .


回答 14

除了递增计数,您还可以递减计数:

  nrToProcess = len(list)
  for s in list:
    s.doStuff()
    nrToProcess -= 1
    if nrToProcess==0:  # this is the last one
      s.doSpecialStuff()

Instead of counting up, you can also count down:

  nrToProcess = len(list)
  for s in list:
    s.doStuff()
    nrToProcess -= 1
    if nrToProcess==0:  # this is the last one
      s.doSpecialStuff()

回答 15

将最后一项的特殊处理延迟到循环之后。

>>> for i in (1, 2, 3):
...     pass
...
>>> i
3

Delay the special handling of the last item until after the loop.

>>> for i in (1, 2, 3):
...     pass
...
>>> i
3

回答 16

可以有多种方式。切片将最快。再添加一个使用.index()方法的对象:

>>> l1 = [1,5,2,3,5,1,7,43]                                                 
>>> [i for i in l1 if l1.index(i)+1==len(l1)]                               
[43]

There can be multiple ways. slicing will be fastest. Adding one more which uses .index() method:

>>> l1 = [1,5,2,3,5,1,7,43]                                                 
>>> [i for i in l1 if l1.index(i)+1==len(l1)]                               
[43]

回答 17

假设输入为迭代器,以下是使用itertools中的tee和izip的方法:

from itertools import tee, izip
items, between = tee(input_iterator, 2)  # Input must be an iterator.
first = items.next()
do_to_every_item(first)  # All "do to every" operations done to first item go here.
for i, b in izip(items, between):
    do_between_items(b)  # All "between" operations go here.
    do_to_every_item(i)  # All "do to every" operations go here.

演示:

>>> def do_every(x): print "E", x
...
>>> def do_between(x): print "B", x
...
>>> test_input = iter(range(5))
>>>
>>> from itertools import tee, izip
>>>
>>> items, between = tee(test_input, 2)
>>> first = items.next()
>>> do_every(first)
E 0
>>> for i,b in izip(items, between):
...     do_between(b)
...     do_every(i)
...
B 0
E 1
B 1
E 2
B 2
E 3
B 3
E 4
>>>

Assuming input as an iterator, here’s a way using tee and izip from itertools:

from itertools import tee, izip
items, between = tee(input_iterator, 2)  # Input must be an iterator.
first = items.next()
do_to_every_item(first)  # All "do to every" operations done to first item go here.
for i, b in izip(items, between):
    do_between_items(b)  # All "between" operations go here.
    do_to_every_item(i)  # All "do to every" operations go here.

Demo:

>>> def do_every(x): print "E", x
...
>>> def do_between(x): print "B", x
...
>>> test_input = iter(range(5))
>>>
>>> from itertools import tee, izip
>>>
>>> items, between = tee(test_input, 2)
>>> first = items.next()
>>> do_every(first)
E 0
>>> for i,b in izip(items, between):
...     do_between(b)
...     do_every(i)
...
B 0
E 1
B 1
E 2
B 2
E 3
B 3
E 4
>>>

回答 18

我想到的最简单的解决方案是:

for item in data_list:
    try:
        print(new)
    except NameError: pass
    new = item
print('The last item: ' + str(new))

因此,我们总是通过延迟处理一次迭代来向前看一项。要跳过第一次迭代期间的操作,我只是捕捉到了错误。

当然,您需要考虑一下,以便在NameError需要时提出它。

同时保持`counstruct

try:
    new
except NameError: pass
else:
    # continue here if no error was raised

这依赖于先前未定义新名称。如果您偏执狂,可以new使用以下方法确保不存在:

try:
    del new
except NameError:
    pass

另外,您当然也可以使用if语句(if notfirst: print(new) else: notfirst = True)。但据我所知,开销更大。


Using `timeit` yields:

    ...: try: new = 'test' 
    ...: except NameError: pass
    ...: 
100000000 loops, best of 3: 16.2 ns per loop

所以我希望开销是无法避免的。

The most simple solution coming to my mind is:

for item in data_list:
    try:
        print(new)
    except NameError: pass
    new = item
print('The last item: ' + str(new))

So we always look ahead one item by delaying the the processing one iteration. To skip doing something during the first iteration I simply catch the error.

Of course you need to think a bit, in order for the NameError to be raised when you want it.

Also keep the `counstruct

try:
    new
except NameError: pass
else:
    # continue here if no error was raised

This relies that the name new wasn’t previously defined. If you are paranoid you can ensure that new doesn’t exist using:

try:
    del new
except NameError:
    pass

Alternatively you can of course also use an if statement (if notfirst: print(new) else: notfirst = True). But as far as I know the overhead is bigger.


Using `timeit` yields:

    ...: try: new = 'test' 
    ...: except NameError: pass
    ...: 
100000000 loops, best of 3: 16.2 ns per loop

so I expect the overhead to be unelectable.


回答 19

计数一次,并跟上剩余的项目数:

remaining = len(data_list)
for data in data_list:
    code_that_is_done_for_every_element

    remaining -= 1
    if remaining:
        code_that_is_done_between_elements

这样,您只需评估列表的长度一次。该页面上的许多解决方案似乎都假定长度是预先不可用的,但这不是您的问题的一部分。如果您有长度,请使用它。

Count the items once and keep up with the number of items remaining:

remaining = len(data_list)
for data in data_list:
    code_that_is_done_for_every_element

    remaining -= 1
    if remaining:
        code_that_is_done_between_elements

This way you only evaluate the length of the list once. Many of the solutions on this page seem to assume the length is unavailable in advance, but that is not part of your question. If you have the length, use it.


回答 20

我想到的一个简单的解决方案是:

for i in MyList:
    # Check if 'i' is the last element in the list
    if i == MyList[-1]:
        # Do something different for the last
    else:
        # Do something for all other elements

第二个同样简单的解决方案可以通过使用计数器来实现:

# Count the no. of elements in the list
ListLength = len(MyList)
# Initialize a counter
count = 0

for i in MyList:
    # increment counter
    count += 1
    # Check if 'i' is the last element in the list
    # by using the counter
    if count == ListLength:
        # Do something different for the last
    else:
        # Do something for all other elements

One simple solution that comes to mind would be:

for i in MyList:
    # Check if 'i' is the last element in the list
    if i == MyList[-1]:
        # Do something different for the last
    else:
        # Do something for all other elements

A second equally simple solution could be achieved by using a counter:

# Count the no. of elements in the list
ListLength = len(MyList)
# Initialize a counter
count = 0

for i in MyList:
    # increment counter
    count += 1
    # Check if 'i' is the last element in the list
    # by using the counter
    if count == ListLength:
        # Do something different for the last
    else:
        # Do something for all other elements

结合FOR循环和IF语句的Python方法

问题:结合FOR循环和IF语句的Python方法

我知道如何在单独的行上同时使用for循环和if语句,例如:

>>> a = [2,3,4,5,6,7,8,9,0]
... xyz = [0,12,4,6,242,7,9]
... for x in xyz:
...     if x in a:
...         print(x)
0,4,6,7,9

而且我知道当语句很简单时,我可以使用列表推导来组合这些内容,例如:

print([x for x in xyz if x in a])

但是,我找不到任何地方(复制和学习)的好例子,展示了一组复杂的命令(不仅是“ print x”),这些命令是在for循环和某些if语句组合后发生的。我期望的是:

for x in xyz if x not in a:
    print(x...)

难道这不是python应该工作的方式吗?

I know how to use both for loops and if statements on separate lines, such as:

>>> a = [2,3,4,5,6,7,8,9,0]
... xyz = [0,12,4,6,242,7,9]
... for x in xyz:
...     if x in a:
...         print(x)
0,4,6,7,9

And I know I can use a list comprehension to combine these when the statements are simple, such as:

print([x for x in xyz if x in a])

But what I can’t find is a good example anywhere (to copy and learn from) demonstrating a complex set of commands (not just “print x”) that occur following a combination of a for loop and some if statements. Something that I would expect looks like:

for x in xyz if x not in a:
    print(x...)

Is this just not the way python is supposed to work?


回答 0

您可以使用以下生成器表达式

gen = (x for x in xyz if x not in a)

for x in gen:
    print x

You can use generator expressions like this:

gen = (x for x in xyz if x not in a)

for x in gen:
    print x

回答 1

按照《 Python的禅宗》(如果您想知道代码是否是“ Pythonic”,那就去吧):

  • 美丽胜于丑陋。
  • 显式胜于隐式。
  • 简单胜于复杂。
  • 扁平比嵌套更好。
  • 可读性很重要。

获得两个s 的Pythonic方法是:sorted intersectionset

>>> sorted(set(a).intersection(xyz))
[0, 4, 6, 7, 9]

或那些xyz不在中的元素a

>>> sorted(set(xyz).difference(a))
[12, 242]

但是对于更复杂的循环,您可能希望通过迭代名称良好的生成器表达式和/或调出名称良好的函数来使其扁平化。试图将所有内容都放在一条线上很少是“ Pythonic”的。


在对您的问题和已接受的答案进行其他评论后进行更新

我不确定您要使用的是什么enumerate,但是如果a是字典,则可能要使用这些键,如下所示:

>>> a = {
...     2: 'Turtle Doves',
...     3: 'French Hens',
...     4: 'Colly Birds',
...     5: 'Gold Rings',
...     6: 'Geese-a-Laying',
...     7: 'Swans-a-Swimming',
...     8: 'Maids-a-Milking',
...     9: 'Ladies Dancing',
...     0: 'Camel Books',
... }
>>>
>>> xyz = [0, 12, 4, 6, 242, 7, 9]
>>>
>>> known_things = sorted(set(a.iterkeys()).intersection(xyz))
>>> unknown_things = sorted(set(xyz).difference(a.iterkeys()))
>>>
>>> for thing in known_things:
...     print 'I know about', a[thing]
...
I know about Camel Books
I know about Colly Birds
I know about Geese-a-Laying
I know about Swans-a-Swimming
I know about Ladies Dancing
>>> print '...but...'
...but...
>>>
>>> for thing in unknown_things:
...     print "I don't know what happened on the {0}th day of Christmas".format(thing)
...
I don't know what happened on the 12th day of Christmas
I don't know what happened on the 242th day of Christmas

As per The Zen of Python (if you are wondering whether your code is “Pythonic”, that’s the place to go):

  • Beautiful is better than ugly.
  • Explicit is better than implicit.
  • Simple is better than complex.
  • Flat is better than nested.
  • Readability counts.

The Pythonic way of getting the sorted intersection of two sets is:

>>> sorted(set(a).intersection(xyz))
[0, 4, 6, 7, 9]

Or those elements that are xyz but not in a:

>>> sorted(set(xyz).difference(a))
[12, 242]

But for a more complicated loop you may want to flatten it by iterating over a well-named generator expression and/or calling out to a well-named function. Trying to fit everything on one line is rarely “Pythonic”.


Update following additional comments on your question and the accepted answer

I’m not sure what you are trying to do with enumerate, but if a is a dictionary, you probably want to use the keys, like this:

>>> a = {
...     2: 'Turtle Doves',
...     3: 'French Hens',
...     4: 'Colly Birds',
...     5: 'Gold Rings',
...     6: 'Geese-a-Laying',
...     7: 'Swans-a-Swimming',
...     8: 'Maids-a-Milking',
...     9: 'Ladies Dancing',
...     0: 'Camel Books',
... }
>>>
>>> xyz = [0, 12, 4, 6, 242, 7, 9]
>>>
>>> known_things = sorted(set(a.iterkeys()).intersection(xyz))
>>> unknown_things = sorted(set(xyz).difference(a.iterkeys()))
>>>
>>> for thing in known_things:
...     print 'I know about', a[thing]
...
I know about Camel Books
I know about Colly Birds
I know about Geese-a-Laying
I know about Swans-a-Swimming
I know about Ladies Dancing
>>> print '...but...'
...but...
>>>
>>> for thing in unknown_things:
...     print "I don't know what happened on the {0}th day of Christmas".format(thing)
...
I don't know what happened on the 12th day of Christmas
I don't know what happened on the 242th day of Christmas

回答 2

我个人认为这是最漂亮的版本:

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]
for x in filter(lambda w: w in a, xyz):
  print x

编辑

如果您非常想避免使用lambda,则可以使用部分函数应用程序并使用运算符模块(该模块提供大多数运算符的功能)。

https://docs.python.org/2/library/operator.html#module-operator

from operator import contains
from functools import partial
print(list(filter(partial(contains, a), xyz)))

I personally think this is the prettiest version:

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]
for x in filter(lambda w: w in a, xyz):
  print x

Edit

if you are very keen on avoiding to use lambda you can use partial function application and use the operator module (that provides functions of most operators).

https://docs.python.org/2/library/operator.html#module-operator

from operator import contains
from functools import partial
print(list(filter(partial(contains, a), xyz)))

回答 3

以下是接受的答案的一种简化/一种解释:

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]

for x in (x for x in xyz if x not in a):
    print(x)

12
242

请注意,generator保持内联。已在python2.7python3.6 (请注意print;)中的括号中对此进行了测试)

The following is a simplification/one liner from the accepted answer:

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]

for x in (x for x in xyz if x not in a):
    print(x)

12
242

Notice that the generator was kept inline. This was tested on python2.7 and python3.6 (notice the parens in the print ;) )


回答 4

我可能会使用:

for x in xyz: 
    if x not in a:
        print x...

I would probably use:

for x in xyz: 
    if x not in a:
        print x...

回答 5

a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]  
set(a) & set(xyz)  
set([0, 9, 4, 6, 7])
a = [2,3,4,5,6,7,8,9,0]
xyz = [0,12,4,6,242,7,9]  
set(a) & set(xyz)  
set([0, 9, 4, 6, 7])

回答 6

如果生成器表达式变得过于复杂或复杂,您也可以使用生成器:

def gen():
    for x in xyz:
        if x in a:
            yield x

for x in gen():
    print x

You can use generators too, if generator expressions become too involved or complex:

def gen():
    for x in xyz:
        if x in a:
            yield x

for x in gen():
    print x

回答 7

使用intersectionintersection_update

  • 交叉点

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    ans = sorted(set(a).intersection(set(xyz)))
  • junction_update

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    b = set(a)
    b.intersection_update(xyz)

    b是你的答案

Use intersection or intersection_update

  • intersection :

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    ans = sorted(set(a).intersection(set(xyz)))
    
  • intersection_update:

    a = [2,3,4,5,6,7,8,9,0]
    xyz = [0,12,4,6,242,7,9]
    b = set(a)
    b.intersection_update(xyz)
    

    then b is your answer


回答 8

我喜欢Alex的答案,因为过滤器恰好是应用于列表的if,所以如果您想探索给定条件的列表子集,这似乎是最自然的方法

mylist = [1,2,3,4,5]
another_list = [2,3,4]

wanted = lambda x:x in another_list

for x in filter(wanted, mylist):
    print(x)

此方法对于分离关注点很有用,如果条件函数发生变化,则唯一需要摆弄的代码就是函数本身

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

for x in filter(wanted, mylist):
    print(x)

当您不希望列表的成员时,使用generator方法似乎更好,但是可以对所述成员进行修改,这似乎更适合生成器

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.5 for x in mylist if wanted(x))

for x in generator:
    print(x)

此外,过滤器可与生成器一起使用,尽管在这种情况下效率不高

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.9 for x in mylist)

for x in filter(wanted, generator):
    print(x)

但是,当然,这样写仍然会很好:

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

# for x in filter(wanted, mylist):
for x in mylist if wanted(x):
    print(x)

I liked Alex’s answer, because a filter is exactly an if applied to a list, so if you want to explore a subset of a list given a condition, this seems to be the most natural way

mylist = [1,2,3,4,5]
another_list = [2,3,4]

wanted = lambda x:x in another_list

for x in filter(wanted, mylist):
    print(x)

this method is useful for the separation of concerns, if the condition function changes, the only code to fiddle with is the function itself

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

for x in filter(wanted, mylist):
    print(x)

The generator method seems better when you don’t want members of the list, but a modification of said members, which seems more fit to a generator

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.5 for x in mylist if wanted(x))

for x in generator:
    print(x)

Also, filters work with generators, although in this case it isn’t efficient

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

generator = (x**0.9 for x in mylist)

for x in filter(wanted, generator):
    print(x)

But of course, it would still be nice to write like this:

mylist = [1,2,3,4,5]

wanted = lambda x:(x**0.5) > 10**0.3

# for x in filter(wanted, mylist):
for x in mylist if wanted(x):
    print(x)

回答 9

查找列表a和b的唯一公共元素的简单方法:

a = [1,2,3]
b = [3,6,2]
for both in set(a) & set(b):
    print(both)

A simple way to find unique common elements of lists a and b:

a = [1,2,3]
b = [3,6,2]
for both in set(a) & set(b):
    print(both)