Python 获取三维列表中唯一元素的最低索引的高效算法
设置 给出一个列表列表,如以下列表:Python 获取三维列表中唯一元素的最低索引的高效算法,python,algorithm,sorting,Python,Algorithm,Sorting,设置 给出一个列表列表,如以下列表: lll = [] for _ in range(5): ll = [random.sample(range(1, 20), 5), random.sample(range(1, 20), 5), random.sample(range(1, 20), 5)] lll.append(ll) 这可能会给出: [[[1, 15, 12], [8, 5, 13], [1, 9, 12]], [[4, 1,
lll = []
for _ in range(5):
ll = [random.sample(range(1, 20), 5),
random.sample(range(1, 20), 5),
random.sample(range(1, 20), 5)]
lll.append(ll)
这可能会给出:
[[[1, 15, 12], [8, 5, 13], [1, 9, 12]],
[[4, 1, 19], [11, 18, 3], [8, 14, 6]],
[[17, 8, 4], [1, 16, 3], [19, 13, 11]]]
最终目标
我希望获得元素出现的最低索引,并以字典的形式返回此输出,例如:
{0: {1, 17, 19, 4, 8, 11}, 1: {5, 9, 13, 14, 15, 16, 18}, 2: {3, 12, 6}}
例如,在上面的lll
中,8
出现在3个子列表中。但它在单个子列表中的最低位置是0
,这就是为什么它会出现在最后一个字典中的0
约束
{0: [1, 8, 4, 19, 11, 17], 1: [15, 5, 13, 9, 18, 14, 16], 2: [12, 3, 6]}
{0: {1, 4, 8, 11, 17, 19}, 1: {5, 9, 13, 14, 15, 16, 18}, 2: {3, 12, 6}}
我必须迭代lll
(我的用例假设我不知道完整的lll
)。因此,遍历\u dct
将随着时间的推移而增加。上述lll
是用于演示的虚拟数据
工作解决方案
目前的方法是有效的,但我相信它会更有效
traversal_dct = {}
for ll in lll:
llT = [*map(list, zip(*ll))]
for i,xs in enumerate(llT):
if i not in traversal_dct.keys():
traversal_dct[i] = set()
traversal_dct[i] = traversal_dct[i].union(set(xs))
for i1,key1 in enumerate(traversal_dct.keys()):
for i2,key2 in enumerate(traversal_dct.keys()):
if i2 > i1:
traversal_dct[i2] = traversal_dct[i2] - traversal_dct[i1]
我觉得你让事情变得更难了 不管你有多少尺寸,把它展平到2D;您没有使用比三元素列表更深层的内容 现在只需列出集合,每个维度中的元素
e = [set(row[col] for row in 2d_list) for col in range(len(2d_list[0]))]
现在,从这些集合中减去之前的集合
e[1] -= e[0]
e[2] -= e[0] + e[1]
。。。您还可以在循环中对其进行参数化。IIUC,您可以执行以下操作:
lll = [[[1, 15, 12], [8, 5, 13], [1, 9, 12]],
[[4, 1, 19], [11, 18, 3], [8, 14, 6]],
[[17, 8, 4], [1, 16, 3], [19, 13, 11]]]
def flatten(lst):
"""Flatten an arbitrary nested list, if the element is not a list return its position"""
for i, e in enumerate(lst):
if isinstance(e, list):
yield from flatten(e)
else:
yield (i, e)
# create a dictionary of value -> min-pos
d = {}
for i, e in flatten(lll):
d[e] = i if e not in d else min(d[e], i)
# reverse the dictionary
reverse = {}
for key, value in d.items():
reverse.setdefault(value, []).append(key)
print(reverse)
输出
{0: [1, 8, 4, 19, 11, 17], 1: [15, 5, 13, 9, 18, 14, 16], 2: [12, 3, 6]}
{0: {1, 4, 8, 11, 17, 19}, 1: {5, 9, 13, 14, 15, 16, 18}, 2: {3, 12, 6}}
如果要将列表转换为集合,请执行以下操作:
result = {key : set(value) for key, value in reverse.items()}
print(result)
输出
{0: [1, 8, 4, 19, 11, 17], 1: [15, 5, 13, 9, 18, 14, 16], 2: [12, 3, 6]}
{0: {1, 4, 8, 11, 17, 19}, 1: {5, 9, 13, 14, 15, 16, 18}, 2: {3, 12, 6}}
您可以维护两个词典:
- 一个用于跟踪每个值的最小索引
- 一个用于跟踪索引->值集映射
ll
,您可以根据(展平的)ll
的长度在时间上进行更新,而无需重建整个遍历字典:
from collections import defaultdict
min_pos = defaultdict(int)
traversal_dict = defaultdict(set)
for ll in lll: # assume this is streamed / iterated
for l in ll:
for (i, val) in enumerate(l):
if val not in min_pos: # O(1) to update both dictionaries
min_pos[val] = i
traversal_dict[i].add(val)
elif i < min_pos[val]:
traversal_dict[min_pos[val]].remove(val)
min_pos[val] = i
traversal_dict[i].add(val)
print traversal_dict # retrieve answer after each iteration
您需要多久返回一次答案?是每次迭代还是在您完成对lll
的所有元素的迭代之后?始终是3级深度?@滑块每次iteration@Daniel_Mesejo,不,它是可变的,这几乎让我想起了一个小堆,所以如果你需要一直把它泡起来,我会用这种方法。如果不是,您仍然需要访问完整的项目集,因此它的运行时仍然为n,其中n是单元格/项目的完整计数。