如何将多层嵌套可迭代对象压缩为单次可迭代元组集合
处理嵌套层级不一致的可迭代对象
核心定义
若对象所有元素均为可迭代对象,则为多次可迭代;
若对象所有元素均不可迭代,则为单次可迭代;
若对象元素均为含非可迭代元素的可迭代对象,则为两次可迭代,例如((1,),(1,2,),(1,2,3,))。
输入示例
trie_like= ( ((((('a','b','c','d'),), (('a','b','c','e'),),), ((('a','b','d','e'),),),), (((('a','c','d','e'),),),),), ((((('b','c','d','e'),),),),), ) uneven = (((1,),(2,),(3,)),((1,2,3),), (12,34),)
需求
编写函数降低嵌套层级,将原始对象解包至两次可迭代层级,即压缩后的可迭代对象每个元素均为单次可迭代元组。预期输出:
trie_like_condensed = (('a','b','c','d'),('a','b','c','e'),('a','b','d','e'), ('a','c','d','e'),('b','c','d','e'),) uneven_condensed = ((1,),(2,),(3,),(1,2,3),(12,34),)
尝试过的方法及问题
反复调用
itertools.chain.from_iterable:无法确定终止条件,仅适配嵌套深度完全一致的对象,对于层级不均的输入会过度展开或展开不足。import itertools from collections.abc import Iterable t = ( ((((('a','b','c','d'),), (('a','b','c','e'),),), ((('a','b','d','e'),),),), (((('a','c','d','e'),),),),), ((((('b','c','d','e'),),),),),) count = 0 # 防止无限循环 while isinstance(t,Iterable) and count<20: count = count + 1 t,p = itertools.tee(itertools.chain.from_iterable(t)) print(list(p)) print(*map("".join, t))itertools.takewhile递归实现:未正确区分需要保留的层级和需要展开的层级,逻辑混乱导致无法得到预期结果。import itertools from collections.abc import Iterable def unnest_iterables(t,count=0): iter_part = itertools.takewhile(lambda x: isinstance(x,Iterable),t) niter_part = itertools.takewhile(lambda x: not isinstance(x,Iterable),t) # 复制迭代器用于打印 iter_part,p = itertools.tee(iter_part) niter_part,pn = itertools.tee(niter_part) print(f'Depth = {count}: {list(p)} : {list(pn)}') if count > 10: print('TEST: Big oof') return [] try: return unnest_iterables(itertools.chain(itertools.chain.from_iterable(iter_part),niter_part),count+1) except StopIteration: return itertools.chain(itertools.chain.from_iterable(iter_part),niter_part) t = ( (((((1,2,3,4),), ((1,2,3,5),),), (((1,2,4,5),),),), ((((1,3,4,5),),),),), (((((2,3,4,5),),),),),) print(*unnest_iterables(t))
解决方案
通过递归遍历,判断每个元素是否需要继续展开:仅当元素是多次可迭代(自身可迭代且所有子元素均为可迭代)时,才递归展开;否则直接保留该元素(已符合单次可迭代的要求)。
from collections.abc import Iterable def flatten_to_single_iterables(iterable): result = [] for item in iterable: # 判断当前元素是否为多次可迭代:需要继续展开 if isinstance(item, Iterable) and all(isinstance(sub, Iterable) for sub in item): result.extend(flatten_to_single_iterables(item)) else: # 当前元素已是单次可迭代,直接保留 result.append(item) return tuple(result)
测试验证
# 测试trie_like trie_like= ( ((((('a','b','c','d'),), (('a','b','c','e'),),), ((('a','b','d','e'),),),), (((('a','c','d','e'),),),),), ((((('b','c','d','e'),),),),), ) print(flatten_to_single_iterables(trie_like)) # 输出:(('a', 'b', 'c', 'd'), ('a', 'b', 'c', 'e'), ('a', 'b', 'd', 'e'), ('a', 'c', 'd', 'e'), ('b', 'c', 'd', 'e')) # 测试uneven uneven = (((1,),(2,),(3,)),((1,2,3),), (12,34),) print(flatten_to_single_iterables(uneven)) # 输出:((1,), (2,), (3,), (1, 2, 3), (12, 34))
逻辑说明
- 遍历输入的每个元素,检查其是否属于需要继续展开的“多次可迭代”类型;
- 对于需要展开的元素,递归处理后将结果合并到最终列表;
- 对于不需要展开的元素(单次可迭代元组),直接加入结果列表;
- 最终将结果转为元组,符合输入输出的类型一致性。
内容的提问来源于stack exchange,提问作者Orion Yeung
相关产品推荐
相关产品推荐

