带有itertools count()和groupby()的lambda函数

有人可以解释groupby操作和this SO帖子上使用的lambda函数吗?带有itertools count()和groupby()的lambda函数

key=lambda k, line=count(): next(line) // chunk

import tempfile 

from itertools import groupby, count

temp_dir = tempfile.mkdtemp()

def tempfile_split(filename, temp_dir, chunk=4000000):

with open(filename, 'r') as datafile:

# The itertools.groupby() function takes a sequence and a key function,

# and returns an iterator that generates pairs.

# Each pair contains the result of key_function(each item) and

# another iterator containing all the items that shared that key result.

groups = groupby(datafile, key=lambda k, line=count(): next(line) // chunk)

for k, group in groups:

print(key, list(group))

output_name = os.path.normpath(os.path.join(temp_dir + os.sep, "tempfile_%s.tmp" % k))

for line in group:

with open(output_name, 'a') as outfile:

outfile.write(line)

编辑:我花了一段时间来回绕与GROUPBY使用lambda函数我的头。我不认为我很了解他们中的任何一个。

Martijn解释得很好,但我有一个后续问题。为什么line=count()每次都作为lambda函数的参数传递?我试图在变量的外部分配变量linecount()一次。

line = count() 

groups = groupby(datafile, key=lambda k, line: next(line) // chunk)

和它导致TypeError: <lambda>() missing 1 required positional argument: 'line'

另外,直接在λ表达式呼吁count()next,导致在输入文件中的所有行得到聚集在一起,即由groupby函数生成的单个密钥。

groups = groupby(datafile, key=lambda k: next(count()) // chunk) 

我自己学习Python,所以任何帮助或指向参考材料/ PyCon会谈的指针都非常感谢。任何真的!

回答:

itertools.count()是一个递增整数的无限迭代器。

lambda将实例存储为关键字参数,所以每次调用lambda时本地变量line都会引用该对象。 next()前进一个迭代,检索下一个值:

>>> from itertools import count 

>>> line = count()

>>> next(line)

0

>>> next(line)

1

>>> next(line)

2

>>> next(line)

3

所以next(line)检索序列中的下一个计数,并且通过chunk(只取除法的整数部分)除以该值。 k参数被忽略。

因为使用了整数除法,所以lambda的结果将是chunk重复递增的整数;如果chunk是3,那么你得到0三次,然后1三次,然后2三次,等:

>>> chunk = 3 

>>> l = lambda k, line=count(): next(line) // chunk

>>> [l('ignored') for _ in range(10)]

[0, 0, 0, 1, 1, 1, 2, 2, 2, 3]

>>> chunk = 4

>>> l = lambda k, line=count(): next(line) // chunk

>>> [l('ignored') for _ in range(10)]

[0, 0, 0, 0, 1, 1, 1, 1, 2, 2]

正是这导致值groupby()datafile迭代的,生产的chunk线组。

当通过groupby()结果与for k, group in groups:循环,k在于lambda产生,结果按分组的数目;代码中的for循环忽略了这一点。 group是来自datafile的行的迭代,并且将始终包含chunk行。

回答:

为了响应更新的OP ...

itertools.groupby迭代器提供了将项目组合在一起的方法,在定义键函数时提供更多控制。请参阅how itertools.groupby() works。

lambda函数是编写常规函数的功能性的简写方式。例如:

>>> keyfunc = lambda k, line=count(): next(line) 

等效于此常规功能:

>>> def keyfunc(k, line=count()): 

... return next(line) // chunk

关键词:迭代器,函数式编程,匿名函数


详细

为什么line=count()每次都作为参数传递给lambda函数?

原因与普通功能相同。 line参数本身是一个位置参数。当赋值时,它将成为默认关键字参数。查看更多关于positional vs. keyword arguments。

您仍然可以通过分配结果关键字参数定义line=count()之外的功能:

>>> chunk = 3 

>>> line=count()

>>> keyfunc = lambda k, line=line: next(line) // chunk # make `line` a keyword arg

>>> [keyfunc("") for _ in range(10)]

[0, 0, 0, 1, 1, 1, 2, 2, 2, 3]

>>> [keyfunc("") for _ in range(10)]

[3, 3, 4, 4, 4, 5, 5, 5, 6, 6] # note `count()` continues

...直接在lambda表达式调用next上count(),导致了所有行输入文件中获取聚集在一起,即是由groupby函数生成一个密钥...

尝试以下实验count()

>>> numbers = count() 

>>> next(numbers)

0

>>> next(numbers)

1

>>> next(numbers)

2

正如预期的那样,你会发现next()count()迭代器产生的下一个项目。 (一个类似的函数被称为迭代器,用for循环迭代)。这里唯一的是发电机不会重置 - next()只是给出该行中的下一项(如前例所示)。

@Martijn Pieters指出next(line) // chunk计算一个Flooring整数,groupby使用该整数来标识每条线(将相似的ID集中在一起的相似线条),这也是预期的。有关groupby如何工作的更多信息,请参阅参考资料。

参考

  • Docs for itertools.count
  • Docs for itertools.groupby()
  • 比兹利,D和琼斯,B. “在匿名函数7.7捕捉变量,” Python的食谱,第三版。奥赖利。 2013。

以上是 带有itertools count()和groupby()的lambda函数 的全部内容, 来源链接: utcz.com/qa/266282.html

回到顶部