【问题标题】:merging n sorted lists of tuples in python在python中合并n个排序的元组列表
【发布时间】:2011-02-15 04:46:17
【问题描述】:

我有 n 个元组列表 (n

Example Input:
[('A',[(0.12, 'how'),(0.26,'are'),(0.7, 'you'),(0.9,'mike'),(1.9, "I'm fine too")]),
('B',[(1.23, 'fine'),(1.50, 'thanks'),(1.6,'and you')]),
('C',[(2.12,'good'),(2.24,'morning'),(3.13,'guys')])]

Desired Output:
[('A', ( 0.12, 'how')),
('A', ( 0.26, 'are')),
('A', ( 0.7, 'you')),
('A', ( 0.9, 'mike')),
('B',(1.23, 'fine')),
('B',(1.50, 'thanks')),
('B',(1.6,'and you')),
('A', (1.9, "I'm fine too")),
('C',(2.12,'good')),
('C',(2.24,'morning')),
('C',(3.13,'guys'))]   

我知道代码很难看,尤其是那些索引 item[0][-1][1],但是有人能告诉我我做错了什么吗?

content = []    
max = 0.0
first = True 
Done = False
finished = []
while not Done:
    for item in flow:
        if len(finished) == 4:
            Done = True
            break
        if len(item[1]) == 0:
            if item[0] not in finished:
                finished.append(item[0])
            continue
        if first == True:
            max = item[1][-1][0]
            content.append((item[0], item[1].pop()))
            first = False 
            continue
        if item[1][-1][0] > max:
            max = item[1][-1][0]
            content.append((item[0], item[1].pop()))
            content = sorted(content, key=itemgetter(1))    

    first = True    

更新: 谢谢大家

【问题讨论】:

  • Timsort 对于部分排序的数据非常快。你的工作量太大了。
  • 不要使用max作为变量名,你可能希望有一天能够使用内置函数max()
  • 听起来你想做的很简单,但你给我们的只是一些令人困惑的输出,甚至不是python结构,也没有示例输入。例如,在您的输出中,列表 ID 都分组在一起。请提供一些有效的 python 数据结构来显示输入和所需的输出

标签: python algorithm sorting tuples merge


【解决方案1】:
>>> from operator import itemgetter
>>> import pprint
>>> pprint.pprint(sorted(((i,k) for i,j in INPUT for k in j), key=itemgetter(1)))
[('A', (0.12, 'how')),
 ('A', (0.26000000000000001, 'are')),
 ('A', (0.69999999999999996, 'you')),
 ('A', (0.90000000000000002, 'mike')),
 ('B', (1.23, 'fine')),
 ('B', (1.5, 'thanks')),
 ('B', (1.6000000000000001, 'and you')),
 ('A', (1.8999999999999999, "I'm fine")),
 ('C', (2.1200000000000001, 'good')),
 ('C', (2.2400000000000002, 'morning')),
 ('C', (3.1299999999999999, 'guys'))]

这里主要有两件事情发生

[(i,k) for i,j in INPUT for k in j]

将INPUT转换成这个结构

[('A', (0.12, 'how')),
 ('A', (0.26, 'are')),
 ('A', (0.7, 'you')),
 ('A', (0.9, 'mike')),
 ('A', (1.9, "I'm fine")),
 ('B', (1.23, 'fine')),
 ('B', (1.5, 'thanks')),
 ('B', (1.6, 'and you')),
 ('C', (2.12, 'good')),
 ('C', (2.24, 'morning')),
 ('C', (3.13, 'guys'))]

sorted(L, key=itemgetter(1))

对每个元素的 L buy item[1] 进行排序。这实际上是 (0.12, 'how'), (0.27, 'are') ... 但是python对元组排序的正常方式是从左到右,所以我们不需要做额外的工作来从元组

【讨论】:

  • 提供的示例解决方案表明,问题规范的内容比说明的要多(即空子列表将“结束”该数据集的部分,从而阻止处理该列表的任何后续条目id,以及在完成指定数量的不同数据集后提前终止循环)
  • 就像一个魅力,谢谢。有什么办法可以将它保存到列表中?
  • @mat, sorted() 返回一个列表
【解决方案2】:

(好的,示例数据使问题描述更加清晰。答案相应修改)

第 1 步:通过对当前解决方案进行逆向工程来阐明您的问题描述。

  1. 有 4 个不同的数据集标记为 A、B、C 和 D
  2. 这些数据集包含在一系列 2 元组的形式(ListID、元素)中
  3. 每个“元素”条目本身就是一个 2 元组的列表,格式为(索引、值)
  4. 空元素条目表示数据集结束
  5. 目标是将这些数据集合并成一个 2 元组(ListID、(索引、值))的排序列表

第 2 步:转换输入数据以创建所需形式的单个记录。

生成器是为这种事情而构建的,因此定义一个是有意义的。

def get_data(flow, num_data_sets=4):
    finished = set()
    for list_id, elements in flow:
        if list_id in finished:
            continue
        if not elements:
            finished.add(list_id)
            if len(finished) == num_data_sets:
                break
            continue
        for element in elements:
            yield list_id, element

第 3 步:使用sorted 生成所需的有序列表

content = sorted(get_data(flow))

示例用法:

# get_data defined via copy/paste of source code above
# ref_data taken from the revised question
>>> demo_data = [
...   ('A', [(1, 2), (3, 4)]),
...   ('B', [(7, 8), (9, 10)]),
...   ('A', [(0, 0)]),
...   ('C', []), # Finish early
...   ('C', [('ignored', 'entry')])
... ]
>>> content = sorted(get_data(demo_data))
>>> print '\n'.join(map(str, content))
('A', 0, 0)
('A', 1, 2)
('A', 3, 4)
('B', 7, 8)
('B', 9, 10)
>>> content = sorted(get_data(ref_data), key=itemgetter(1))
>>> print '\n'.join(map(str, content))
('A', 0.12, 'how')
('A', 0.26, 'are')
('A', 0.7, 'you')
('A', 0.9, 'mike')
('B', 1.23, 'fine')
('B', 1.5, 'thanks')
('B', 1.6, 'and you')
('A', 1.9, "I'm fine too")
('C', 2.12, 'good')
('C', 2.24, 'morning')
('C', 3.13, 'guys')

您的解决方案最终变得凌乱且难以阅读,主要原因有两个:

  1. 未能使用生成器意味着您无法充分利用内置排序功能
  2. 通过使用索引而不是元组解包,您很难跟踪什么是什么

【讨论】:

    【解决方案3】:
    data = [(x,id) for (id, xs) in data for x in xs]
    data.sort()
    for xs,id in data:
        print id,xs
    
    
    A (0.12, 'how')
    A (0.26000000000000001, 'are')
    A (0.69999999999999996, 'you')
    A (0.90000000000000002, 'mike')
    B (1.23, 'fine')
    B (1.5, 'thanks')
    B (1.6000000000000001, 'and you')
    A (1.8999999999999999, "I'm fine too")
    C (2.1200000000000001, 'good')
    C (2.2400000000000002, 'morning')
    C (3.1299999999999999, 'guys')
    

    【讨论】:

    • 这没有按正确顺序输出( A (1.8999999999999999, "I'm fine too") 应该进一步向下)
    【解决方案4】:

    您的意见:

    l = [('A',
        [(0.12, 'how'),
        (0.26000000000000001, 'are'),
        (0.69999999999999996, 'you'),
        (0.90000000000000002, 'mike'),
        (1.8999999999999999, "I'm fine too")]),
        ('B', [(1.23, 'fine'), (1.5, 'thanks'), (1.6000000000000001, 'and you')]),
        ('C',
        [(2.1200000000000001, 'good'),
        (2.2400000000000002, 'morning'),
        (3.1299999999999999, 'guys')])]
    

    转换(和打印):

    newlist = []
    for alpha, tuplelist in l:
        for tup in tuplelist:
            newlist.append((alpha,tup))
    
    from operator import itemgetter
    sorted(newlist,key=itemgetter(1))
    print newlist
    

    检查!

    [('A', (0.12, 'how')),
     ('A', (0.26000000000000001, 'are')),
     ('A', (0.69999999999999996, 'you')),
     ('A', (0.90000000000000002, 'mike')),
     ('B', (1.23, 'fine')),
     ('B', (1.5, 'thanks')),
     ('B', (1.6000000000000001, 'and you')),
     ('A', (1.8999999999999999, "I'm fine too")),
     ('C', (2.1200000000000001, 'good')),
     ('C', (2.2400000000000002, 'morning')),
     ('C', (3.1299999999999999, 'guys'))]
    

    您当然可以在列表理解中执行此操作,但您仍然使用 2 个 for 循环和 1 个内置 sorted 函数。还不如让它变得冗长和可读。

    【讨论】:

    • 这没有按正确顺序输出( A (1.8999999999999999, "I'm fine too") 应该进一步向下)
    • gnibbler,更新为包括排序。
    猜你喜欢
    • 2018-05-16
    • 2022-11-25
    • 2010-10-02
    • 2010-11-12
    • 1970-01-01
    • 2022-10-05
    • 1970-01-01
    • 2016-07-07
    相关资源
    最近更新 更多