【问题标题】:How to generate list of tuples relating records如何生成相关记录的元组列表
【发布时间】:2013-07-07 15:57:24
【问题描述】:

我需要从元组列表中生成一个列表:

a = [(1,2), (1,3), (2,3), (2,5), (2,6), (3,4), (3,6), (4,7), (5 6), (5,9), (5,10), (6,7)
             (6.10) (6.11) (7.8) (7.12) (8.12) (9.10) (10.11)]

规则是: - 我有任何 (begin = random.choice (a)) 的记录 - 新列表中的项目必须具有以下关系: 列表中每个元组的最后一项必须等于要插入的下一个元组的第一项。

有效输出示例(从元组 (3.1) 开始):

[(3, 1), (1, 2), (2, 3), (3, 4), (4, 7), (7, 8), (8, 12), (12, 7), (7, 6), (6, 2), (2, 5), (5, 6), (6, 10), (10, 5) (5, 9), (9, 10), (10, 11), (11, 6), (6, 3)]

我该怎么做?它使用列表推导吗? 谢谢!

【问题讨论】:

  • 为什么不包括(6, 7)(6, 3) 哪里来的?
  • 我不明白您如何在输出中获取 (8, 12) 之后的值。您是否正在向后扫描a 列表?否则正确的输出将只是[(1, 2), (2, 3), (3, 4), (4, 7), (7, 8), (8, 12)]
  • @Bakuriu,好吧,确切的输出取决于随机的begin 元组。但是,是的,输出列表不包括所有原始元组。

标签: python list tuples


【解决方案1】:

在这里,lisb 将按照您查找的顺序填充元组。当然,如果lisa 提供了适当的元组(即,每个元组的第一个值与另一个元组的第0 个值匹配)。无论实现如何,您的示例列表都将不起作用,因为所有值都不匹配(例如,没有第 0 个元素为 12,因此元组无法连接到任何其他元组)...所以你应该想出一个更好的样本列表。

经过测试,工作正常。

import random

lisa = [(1, 2), (3, 4), (2, 3), (4, 0), (0, 9), (9, 1)]
lisb = []

current = random.choice(lisa)

while True:
    lisa.remove(current)
    lisb.append(current)
    current = next((y for y in lisa if y[0] == current[1]), None)
    if current == None:
        break

print lisb

如果您不想从 lisa 中删除项目,只需切片一个新列表。

【讨论】:

  • 您可以存储current 的索引,而不是lista.remove(current),并使用lisa[idx] = lisa[-1]; lisa.pop() 将其删除。这种移除不是线性的,而是恒定的时间。
  • @kroolik 是的,但是 list.index() 是线性运算。因此,这两种复杂性最终都会成为线性时间。
  • 经过一些测试:python -m timeit "a = range(100000); a.remove(50000)" 每个循环产生 1.69 毫秒,python -m timeit "a = range(100000); a.remove(1)" 每个循环产生 986 微秒,python -m timeit "a = range(100000); a.remove(99999)" 每个循环产生 2.41 毫秒。 index switch 和 pop() 在所有情况下都产生了 908~ usec
【解决方案2】:

作为生成器函数:

def chained_tuples(x):
    oldlist = x[::]
    item = random.choice(oldlist)
    oldlist.remove(item)
    yield item

    while oldlist:
        item = next(next_item for next_item in oldlist if next_item[0] == item[1])
        oldlist.remove(item)
        yield item

如前所述,如果您的列表实际上并不是一直可链接的,就像您的示例列表一样,您将得到一个不完整的响应。

【讨论】:

    【解决方案3】:

    只是添加另一种解决此问题的方法:

    import random
    from collections import defaultdict
    
    lisa = [(1, 2), (3, 4), (2, 3), (4, 0), (0, 9), (9, 1)]
    
    current_start, current_end = lisa[random.randint(0, len(lisa) - 1)]
    starts = defaultdict(list)
    lisb = [(current_start, current_end)]
    
    for start, end in lisa:
        starts[start].append(end)
    
    while True:
        if not starts[current_end]:
            break
        current_start, current_end = current_end, starts[current_end].pop()
        lisb.append((current_start, current_end))
    

    注意:您必须确保lisa 不为空。

    【讨论】:

      【解决方案4】:

      我认为到目前为止的所有答案都缺少找到最长链的要求(至少基于您的示例输出)。

      我建议的解决方案是递归解析所有可能构造的链,并返回最长的结果。函数如下所示:

      def generateTuples(list, offset, value = None):
        if value == None: value = list[offset]
        list = list[:offset]+list[offset+1:]
        res = []
        for i,(a,b) in enumerate(list):
          if value[1] in (a,b):
            if value[1] == a:  
              subres = generateTuples(list, i, (a,b))
            else:
              subres = generateTuples(list, i, (b,a))
            if len(subres) > len(res):
              res = subres
        return [value] + res
      

      你会这样称呼它:

      results = generateTuples(a, 1, (3,1))
      

      制作清单:

      [(3, 1), (1, 2), (2, 3), (3, 4), (4, 7), (7, 8), (8, 12), (12, 7), (7, 6),
       (6, 2), (2, 5), (5, 6), (6, 10), (10, 5), (5, 9), (9, 10), (10, 11),
       (11, 6), (6, 3)]
      

      函数的第一个参数是元组的源列表,第二个参数是要使用的第一个元素的偏移量,第三个参数是可选的,但允许你覆盖第一个元素的值。后者在您想以相反的顺序开始元组时很有用,就像您在示例中所做的那样。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2018-03-31
        • 1970-01-01
        • 2015-06-22
        • 2011-01-27
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多