没有填充值的zip_longest [英] zip_longest without fillvalue

查看:89
本文介绍了没有填充值的zip_longest的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述



我正在寻找Python的 zip zip_longest 函数之间的中间地带(来自 itertools 模块),它耗尽了所有给定的迭代器,但不填充任何内容。因此,例如,它应该像这样转换元组:


$ b

 (11,12,13) ,(11,21,31,41),
(21,22,23,24), - > (12,22,32,42),
(31,32),(13,23,43),
(41,42,43,44),(24,44)

(为更好的图形对齐而添加的空格)



我通过清理 fillvalue s之后的 zip_longest


$ b

  def zip_discard(* iterables,sentinel = object()) :
return map(
partial(filter,partial(is_not,sentinel)),
zip_longest(* iterables,fillvalue = sentinel))

有没有办法在不引入标记的情况下执行此操作?这可以通过使用 yield 来改善吗?哪种方法看起来效率最高?

解决方案

您的方法很好。我认为使用哨兵很优雅。我可能会认为使用嵌套的生成器表达式会更加pythonic:

  def zip_discard_gen(* iterables,sentinel = object() ):
return((如果条目不是哨兵,则在迭代中输入条目)
在zip_longest(* iterables,fillvalue = sentinel)中迭代)

因为不需要 partial() ne ()



它也更快一些:

  data = [(11,12,13),
(21,22,23,24),
(31,32),
(41,42,

%timeit [zip_discard(* data)中x的列表(x)]
10000循环,最好是3:每循环17.5μs

%timeit [zip_discard_gen(* data)中x的列表(x)]
100000循环,最好是3:每循环14.2μs

编辑

列表理解版本更快一些:

  def zip_ 
return [[如果条目不是sentinel,则为iterable中的条目]
为zip_longest中的iterable(* iterables,fillvalue = sentinel)]

计时:

 %timeit zip_discard_compr(* data)
100000循环,最好是3:每循环6.73微秒

一个Python 2版本:

  from itertools import izip_longest 

SENTINEL = object()

def zip_discard_compr(* iterables):
sentinel = SENTINEL
return [[迭代条目入口不是sentinel的入口]
迭代的izip_longest ,fillvalue = sentinel)]



定时



该版本返回与code $ zip_varlen 相同的数据结构
Tadhg McDonald-Jensen:

  def zip_discard_gen(* iterables,sentinel = object()):
return(tuple([entry for ent ry in iterable如果入口不是sentinel])
for iterable in zip_longest(* iterables,fillvalue = sentinel))

它的速度快了一倍:

 %timeit list(zip_discard_gen(* data))
100000个循环,最好是3:每循环9.37μs

%timeit list(zip_varlen(* data))
10000循环,最好是3:每循环18μs


I am searching for a middle ground between Python's zip and zip_longest functions (from the itertools module), that exhausts all given iterators, but does not fill in anything. So, for example, it should transpose tuples like so:

(11, 12, 13    ),        (11, 21, 31, 41),
(21, 22, 23, 24),  -->   (12, 22, 32, 42),
(31, 32        ),        (13, 23,     43),
(41, 42, 43, 44),        (    24,     44)

(Spaces added for nicer graphical alignment.)

I managed to compose a crude a solution by cleaning out the fillvalues after zip_longest.

def zip_discard(*iterables, sentinel = object()):
    return map(
            partial(filter, partial(is_not, sentinel)), 
            zip_longest(*iterables, fillvalue=sentinel))

Is there a way to do this without introducing the sentinels to begin with? Can this be improved using yield? Which approach seems most efficient?

解决方案

You approach is good. I think using a sentinel is elegant. I might be considered a bit more pythonic to use a nested generator expression:

def zip_discard_gen(*iterables, sentinel=object()):
    return ((entry for entry in iterable if entry is not sentinel)
            for iterable in zip_longest(*iterables, fillvalue=sentinel))

This needs fewer imports because there is no need for partial() or ne().

It is a bit faster too:

data = [(11, 12, 13    ),
        (21, 22, 23, 24),
        (31, 32        ),
        (41, 42, 43, 44)]

%timeit [list(x) for x in zip_discard(*data)]  
10000 loops, best of 3: 17.5 µs per loop

%timeit [list(x) for x in zip_discard_gen(*data)]
100000 loops, best of 3: 14.2 µs per loop

EDIT

A list comprehension version is a bit faster:

def zip_discard_compr(*iterables, sentinel=object()):
    return [[entry for entry in iterable if entry is not sentinel]
            for iterable in zip_longest(*iterables, fillvalue=sentinel)]

Timing:

%timeit zip_discard_compr(*data)
100000 loops, best of 3: 6.73 µs per loop

A Python 2 version:

from itertools import izip_longest

SENTINEL = object()

def zip_discard_compr(*iterables):
    sentinel = SENTINEL
    return [[entry for entry in iterable if entry is not sentinel]
            for iterable in izip_longest(*iterables, fillvalue=sentinel)]

Timings

This version returns the same data structure as zip_varlen by Tadhg McDonald-Jensen:

def zip_discard_gen(*iterables, sentinel=object()):
    return (tuple([entry for entry in iterable if entry is not sentinel])
            for iterable in zip_longest(*iterables, fillvalue=sentinel))

It is about twice as fast:

%timeit list(zip_discard_gen(*data))
100000 loops, best of 3: 9.37 µs per loop

%timeit list(zip_varlen(*data))
10000 loops, best of 3: 18 µs per loop

这篇关于没有填充值的zip_longest的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆