【问题标题】:python:[[1,2],[3,4],[5,6],[7,8]] transform into [[1],[2,3],[4,5],[6,7],[8]] and vice versapython:[[1,2],[3,4],[5,6],[7,8]] 转换为 [[1],[2,3],[4,5],[6,7 ],[8]] 反之亦然
【发布时间】:2010-08-16 19:33:11
【问题描述】:

我目前的解决方案指针是

  • ether 通过生成新组装的内部列表的迭代器类
  • 或通过生成新组装的内部列表的迭代函数

还有其他更好的方法来解决这个挑战吗?

编辑

@Glenn:很好的反对意见。 我没有想到这一点,因为我遇到的列表没有按照我想象的方式排序。

@THC4k:感谢您的解决方案。我学会了chain.from_iterable

@Mike DeSimone:嗯,测试了你的解决方案,但出了点问题,也许我错过了什么,...

@Jamie 和 Odomontois: 感谢您指出更详细的内容

我的目标

我正在锻造一个小算法,它可以转换任务列表 - 对/元组:(start,stop) - 到一个简化的任务列表,其中重叠的任务合并在一起。

一个例外:当一个事件与另一个事件完全重叠时,我的算法失败(s1 s2 e2 e1)

详细说明:

  • 我有一个成对列表“taskList”(课程 学到了 - 元组:)。
  • 每个元组 由 2 个日期时间对象组成:开始 和任务的结束。
  • 重要: 'taskList' 的年表 顺序由开始决定,因为 任务可能重叠
  • 'taskList' 包含几天,因此是日期时间对象

例如,为了便于阅读,只是时间的字符串表示

taskList = [(9:00,10:00),(9:30,11:00),(11:00,12:30),(13:30,14:00),(14:00,18:00)]

最终结果:

result = [(9:00,12:30), (13:30,18:00)]

现在我的想法是,当我以我质疑的方式重新排列“任务列表”时

taskListT1 = [(9:00,),(10:00,9:30),(11:00,11:00),(12:30,13:30),(14:00,14:00),(18:00,)]

现在我可以消除那些 a >= b 的元组 (a,b):

taskListT2 = [(9:00,),(12:30,13:30),(18:00,)]

然后转换回来:

result = [(9:00,12:30), (13:30,18:00)]

【问题讨论】:

  • 您必须提供更多输入/输出示例,以便我们知道您想要做什么
  • 遍历它们并复制。试图弄清楚究竟是什么“技巧”会做出这样的事情,这真是太可怕了。你花在试图找出一个很酷的解决方案上的每一分钟都是一分钟,每个未来接触过你的代码的人都将不得不花费一分钟来破译你的小把戏。如果您在编程时它不仅是自动的,请不要这样做。如果您对一种模式非常满意以至于它是自动的,那么您可能还会知道何时使用它以及何时更明确。
  • 如果某个嵌套列表长度 > 2 怎么办?
  • 您确定不应该只存储一个平面列表[1,2,3,4,5,6,7,8],并改变迭代它们的方式而不是来回转换列表吗?
  • 哇,自从我第一次看到这个问题以来,这个问题已经改变了。

标签: python list python-3.x swap


【解决方案1】:

嗯,下面是有yield的解决方案:

# transform forwards
def transform_pairs( lst ):
    it = iter(lst)
    a,last = next(it)
    yield [a]
    for a,b in it:
        yield last, a
        last = b
    yield [last]

将列表转换回来应该看起来非常相似,但我将把它留给读者。

这是另一个稍微复杂一点的可以双向变换的。它产生元组,因为固定长度的列表是lame

from itertools import chain

def transform( iterable, offset):
    it = chain.from_iterable(iterable) # turn it back to one long list.
    if offset:
        yield next(it), # the trailing `,` makes this a tuple.
    for item in it:
        try:
            x = next(it)
        except StopIteration: # there is no 2nd item left
            yield item,
        else:
             yield item, x # yield the pair

print list(transform(transform([[1,2],[3,4],[5,6],[7,8]], True), False))

【讨论】:

    【解决方案2】:

    寻求“另一种更好的方式”选项(甚至让 OP 的异常正确):

    def compress_task_list(tasks):
        tasks = list(tasks)
        tasks.sort(key=lambda item: item[0]) # make sure list is in order by start time
        result = []
        first_start = tasks[0][0]
        final_stop = tasks[0][1]
        for start, stop in tasks[1:]:
            if start > final_stop:
                result.append((first_start, final_stop))
                first_start = start
                final_stop = stop
            elif stop > final_stop:
                final_stop = stop
        result.append((first_start, final_stop))
        return tuple(result)
    
    if __name__ == '__main__':
        import unittest
    
        class Test_Compress_Task_List(unittest.TestCase):
            def test_01(self):
                "completely separate"
                initial = ((8.0, 9.5), (10.0, 12.0), (13.0, 15.5), (16.0, 17.0))
                expected = ((8.0, 9.5), (10.0, 12.0), (13.0, 15.5), (16.0, 17.0))
                self.assertEqual(compress_task_list(initial), expected)
            def test_02(self):
                "end equals start"
                initial = ((8.0, 9.5), (9.5, 12.0), (13.0, 15.5), (15.5, 17.0))
                expected = ((8.0, 12.0), (13.0, 17.0))
                self.assertEqual(compress_task_list(initial), expected)
            def test_03(self):
                "end equals start (with more empty times)"
                initial = ((8.0, 8.5), (8.5, 10.0), (10.25, 12.0), (12.5, 13.75), (13.75, 15.0), (15.25, 16.0), (16.0, 17.0))
                expected = ((8.0, 10.0), (10.25, 12.0), (12.5, 15.0), (15.25, 17.0))
                self.assertEqual(compress_task_list(initial), expected)
            def test_04(self):
                "out of order, cross-overs, and tasks completely inside other tasks"
                initial = ((8.0, 8.5), (8.0, 10.0), (10.25, 12.0), (10.0, 11.5), (13.0, 15.5), (14.0, 15.0), (16.0, 17.0))
                expected = ((8.0, 12.0), (13.0, 15.5), (16.0, 17.0))
                self.assertEqual(compress_task_list(initial), expected)
    
        unittest.main()
    

    记住,这是 Python,可读性很重要。 ;)

    【讨论】:

      【解决方案3】:

      这行得通,但感觉更像是 Pythonic:

      l = [[1,2], [3,4], [5,6], [7,8]]
      o = []
      last = []
      for a, b in l:
          o.append(last+[a])
          last = [b]
      o.append(last)
      
      print o
      

      打印

      [[1], [2, 3], [4, 5], [6, 7], [8]]
      

      这个身体也可以:

      o = [[l[0][0]]]
      for i in range(len(l)-1):
          o.append([l[i][1], l[i+1][0]])
      o.append([l[-1][1]])
      

      【讨论】:

      • 是的,我确保在其中也使用了 i、l 和 1,以获得最大的可读性! (jk)
      • 你没有使用_。 Perl 的人喜欢那个。
      【解决方案4】:
      l = [[1,2], [3,4], [5,6], [7,8]]
      m = [([] if i==0 else [l[i-1][1]] )+([] if i==len(l) else [l[i][0]]) for i in xrange(len(l)+1)]
      

      【讨论】:

      • @Glenn Maynard 答案的意义适应了问题的意义。
      【解决方案5】:

      你的意思是:

      pairs = [[1,2], [3,4], [5,6], [7,8]]
      print pairs, '->',
      transformed = ([[pairs[0][0]]]+
                     [[a,b] for a,b in zip(
                         (second for first, second in pairs[:-1]),
                         (first for first, second in pairs[1:]))]+
                     [[pairs[-1][-1]]]
                     )
      print transformed
      """ Output:
      [[1, 2], [3, 4], [5, 6], [7, 8]] -> [[1], [2, 3], [4, 5], [6, 7], [8]]
      """
      

      【讨论】:

        【解决方案6】:

        这是一个可以与生成器或列表输入一起使用的生成器,因此您不必将所有内容都保存在内存中:

        def shift_pairs(inPairs):
            lastPair = None
            for pair in inPairs:
                if lastPair:
                    yield [lastPair[1], pair[0]]
                else:
                    yield [pair[0]]
                lastPair = pair
            yield [lastPair[1]]
        

        我必须指出,在 Python 中,固定长度的短列表通常以元组的形式完成:

        def shift_pairs(inPairs):
            lastPair = None
            for pair in inPairs:
                if lastPair:
                    yield (lastPair[1], pair[0])
                else:
                    yield (pair[0],)
                lastPair = pair
            yield (lastPair[1],)
        

        【讨论】:

          猜你喜欢
          • 2020-10-15
          • 1970-01-01
          • 2023-03-25
          • 2010-09-27
          • 1970-01-01
          • 2010-12-03
          • 2011-10-08
          • 2020-10-24
          相关资源
          最近更新 更多