Python - 仅压缩包含数据的列表
Python - zip only lists that contain data
我有一个脚本可以将数据从一种类型转换为另一种类型。
源文件可以有以下一项、两项或全部:位置、旋转和缩放数据。
我的脚本在对输出文件进行转换后将 3 个文件压缩在一起。
在这种情况下,我的源文件只包含位置数据。
所以最后 returned 的列表是:
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
translationData = list(zip(pData, rData, sData))
如果我尝试这个,它会 return []
因为最短的列表是 []
。
如果我尝试:
translationData = list(zip_longest(pData, rData, sData))
我得到:
`[(['-300.2', '600.5'], None, None), (['150.12', '280.7'], None, None), (['19.19', '286.56'], None, None)]`
有没有办法只压缩包含数据的列表,或者从列表的元组中删除 None
?
提前致谢!
您可以使用嵌入在 list-comp 中的 filter
内置函数。
Note: In Python 3 filter
returns an iterator, so you will need to call tuple()
on it. (unlike in py2)
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
from itertools import zip_longest # izip_longest for python 2
[tuple(filter(None, col)) for col in zip_longest(pData, rData, sData)]
结果:
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
我会尝试添加更多变化-bool
,None
,lambda
.
import itertools
from itertools import zip_longest
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
print ([list(filter(bool, col)) for col in zip_longest(pData, rData, sData)])
print ([list(filter(None, col)) for col in zip_longest(pData, rData, sData)])
print ([list(filter(lambda x: x, col)) for col in zip_longest(pData, rData, sData)])
输出-
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
您可以根据 documentation 修改 zip_longest
的纯 Python 版本,并创建一个版本来执行您想要的操作:
from itertools import chain, repeat
class ZipExhausted(Exception):
pass
def zip_longest(*args, **kwds):
# zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
counter = len(args) - 1
def sentinel():
nonlocal counter
if not counter:
raise ZipExhausted
counter -= 1
yield fillvalue
fillers = repeat(fillvalue)
iterators = [chain(it, sentinel(), fillers) for it in args]
try:
while iterators:
res = []
for it in iterators:
value = next(it)
if value != fillvalue:
res.append(value)
yield tuple(res)
except ZipExhausted:
pass
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
translationData = list(zip_longest(pData, rData, sData))
print(translationData)
输出:
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
如果您出于某种原因不想导入或使用列表理解等:
- 对要压缩的列表进行分组(所有列表)
- 然后遍历分组以检查每个分组中是否有任何内容
- 将其中包含数据的一组附加到一起(可压缩)
最后,*通过过滤分组的 zip (*zippable)
alist = ['hoop','joop','goop','loop']
blist = ['homp','jomp','gomp','lomp']
clist = []
dlist = []
allLists = [alist,blist,clist,dlist]
zippable = []
for fullList in allLists:
if fullList:
zippable.append(fullList)
finalList = list(zip(*zippable))
print(finalList)
另一种可能的解决方案
如果列表完全是空的或完全是满的,这将起作用:
>>> list(zip(*(x for x in (pData, rData, sData) if x)))
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
如果你不想要 None
你可以使用 zip_longest
的 key-word 参数 fillvalue
来代替你想要的任何东西,这样你可以获得统一的结果正如@Ale
所指出的
>>> translationData = list(zip_longest(pData, rData, sData, fillvalue=tuple()))
>>> translationData
[(['-300.2', '600.5'], (), ()), (['150.12', '280.7'], (), ()), (['19.19', '286.56'], (), ())]
>>>
如果您使用可变对象作为填充值,请当心,因为如果您更改一个对象,所有对象都会更改,因为它们都是对同一对象的引用
>>> translationData = list(zip_longest(pData, rData, sData,fillvalue=list()))
>>> translationData
[(['-300.2', '600.5'], [], []), (['150.12', '280.7'], [], []), (['19.19', '286.56'], [], [])]
>>> translationData[0][1].append(23)
>>> translationData
[(['-300.2', '600.5'], [23], [23]), (['150.12', '280.7'], [23], [23]), (['19.19', '286.56'], [23], [23])]
>>>
我有一个脚本可以将数据从一种类型转换为另一种类型。 源文件可以有以下一项、两项或全部:位置、旋转和缩放数据。
我的脚本在对输出文件进行转换后将 3 个文件压缩在一起。
在这种情况下,我的源文件只包含位置数据。 所以最后 returned 的列表是:
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
translationData = list(zip(pData, rData, sData))
如果我尝试这个,它会 return []
因为最短的列表是 []
。
如果我尝试:
translationData = list(zip_longest(pData, rData, sData))
我得到:
`[(['-300.2', '600.5'], None, None), (['150.12', '280.7'], None, None), (['19.19', '286.56'], None, None)]`
有没有办法只压缩包含数据的列表,或者从列表的元组中删除 None
?
提前致谢!
您可以使用嵌入在 list-comp 中的 filter
内置函数。
Note: In Python 3
filter
returns an iterator, so you will need to calltuple()
on it. (unlike in py2)
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
from itertools import zip_longest # izip_longest for python 2
[tuple(filter(None, col)) for col in zip_longest(pData, rData, sData)]
结果:
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
我会尝试添加更多变化-bool
,None
,lambda
.
import itertools
from itertools import zip_longest
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
print ([list(filter(bool, col)) for col in zip_longest(pData, rData, sData)])
print ([list(filter(None, col)) for col in zip_longest(pData, rData, sData)])
print ([list(filter(lambda x: x, col)) for col in zip_longest(pData, rData, sData)])
输出-
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
[[['-300.2', '600.5']], [['150.12', '280.7']], [['19.19', '286.56']]]
您可以根据 documentation 修改 zip_longest
的纯 Python 版本,并创建一个版本来执行您想要的操作:
from itertools import chain, repeat
class ZipExhausted(Exception):
pass
def zip_longest(*args, **kwds):
# zip_longest('ABCD', 'xy', fillvalue='-') --> Ax By C- D-
fillvalue = kwds.get('fillvalue')
counter = len(args) - 1
def sentinel():
nonlocal counter
if not counter:
raise ZipExhausted
counter -= 1
yield fillvalue
fillers = repeat(fillvalue)
iterators = [chain(it, sentinel(), fillers) for it in args]
try:
while iterators:
res = []
for it in iterators:
value = next(it)
if value != fillvalue:
res.append(value)
yield tuple(res)
except ZipExhausted:
pass
pData = [['-300.2', '600.5'],['150.12', '280.7'],['19.19', '286.56']]
rData = []
sData = []
translationData = list(zip_longest(pData, rData, sData))
print(translationData)
输出:
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
如果您出于某种原因不想导入或使用列表理解等:
- 对要压缩的列表进行分组(所有列表)
- 然后遍历分组以检查每个分组中是否有任何内容
- 将其中包含数据的一组附加到一起(可压缩)
最后,*通过过滤分组的 zip (*zippable)
alist = ['hoop','joop','goop','loop'] blist = ['homp','jomp','gomp','lomp'] clist = [] dlist = [] allLists = [alist,blist,clist,dlist] zippable = [] for fullList in allLists: if fullList: zippable.append(fullList) finalList = list(zip(*zippable)) print(finalList)
另一种可能的解决方案
如果列表完全是空的或完全是满的,这将起作用:
>>> list(zip(*(x for x in (pData, rData, sData) if x)))
[(['-300.2', '600.5'],), (['150.12', '280.7'],), (['19.19', '286.56'],)]
如果你不想要 None
你可以使用 zip_longest
的 key-word 参数 fillvalue
来代替你想要的任何东西,这样你可以获得统一的结果正如@Ale
>>> translationData = list(zip_longest(pData, rData, sData, fillvalue=tuple()))
>>> translationData
[(['-300.2', '600.5'], (), ()), (['150.12', '280.7'], (), ()), (['19.19', '286.56'], (), ())]
>>>
如果您使用可变对象作为填充值,请当心,因为如果您更改一个对象,所有对象都会更改,因为它们都是对同一对象的引用
>>> translationData = list(zip_longest(pData, rData, sData,fillvalue=list()))
>>> translationData
[(['-300.2', '600.5'], [], []), (['150.12', '280.7'], [], []), (['19.19', '286.56'], [], [])]
>>> translationData[0][1].append(23)
>>> translationData
[(['-300.2', '600.5'], [23], [23]), (['150.12', '280.7'], [23], [23]), (['19.19', '286.56'], [23], [23])]
>>>