带有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函数的参数传递?我试图在变量的外部分配变量line
到count()
一次。
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