【问题标题】:"Splitting" the output of a RLE (groupby) depending on a defined value ( the "character" to split the RLE on )根据定义的值“拆分”RLE(groupby)的输出(拆分 RLE 的“字符”)
【发布时间】:2011-05-17 13:11:41
【问题描述】:

考虑“字符串”(将其视为数字数组)

0 0 1 8 8 8 1 0

RLE(“groupby”)是:

[(0,2), (1, 1), (8,3), (1, 1), (0, 1)]

然后我们用前面元素的游程总和来丰富上述 RLE。

因此,上述内容的丰富版本变为:

[(0, (0,2)), (0+2, (1, 1)), (0+2+1, (8,3)), (0+1+2+3, (1, 1)), (0+1+2+3+1, (0, 1))]

“字符串”在 1 处拆分:

0 0 , 8 8 8 , 0

RLE 在 1 上拆分

[(0,2)] , [(8,3)] , [(0, 1)]

“字符串”在 8 上拆分:

0 0 1 , , , 1 0

RLE 在 8 上拆分

[(0,2), (1, 1)] , , , [(1, 1), (0, 1)]

注意:在我的示例中,我引用了“RLE 在 Z 上拆分”列表,但并未对其进行丰富。事实并非如此。我把它们排除在外以减少混乱。例如,“RLE split on 1”实际上应该被视为:

[(0, (0,2))] , [(0+2+1, (8,3))] , [(0+1+2+3+1, (0, 1)]

我怎样才能在 Z 上实现这种“RLE 拆分”(= 1, 8; 在这种情况下)

可以省略空数组(拆分后)。

也许是一个聪明的列表组合? (使用嵌套了 append 的 for 循环似乎更容易解决)

【问题讨论】:

  • 我很困惑。像0+2+1 这样的表达式应该是一个字符串还是你只是想要3
  • 只有 3 个 - 我想把事情分解成可读性。很抱歉造成混乱!
  • 假设 RLE=[(0,2), (1,1), (8,3), (4,2), (1,1), (0,1)];结果应该是 [(0, (0,2))] , [(0+2+1, (8,3), (4,2) )] , [(0+2 +1+3+2+1, (0, 1)] 或 [(0, (0,2))] , [(0+2+1, (8,3)), (0+2 +1+3, (4,2)) ] , [(0+2+1+3+2+1, (0, 1)]
  • 要获得该 RLE,原始数组需要为 a = [0, 0, 1, 8, 8, 8, 4, 4, 1, 1, 0]。在那种情况下,这就是我所拥有的get_rle(a) -> [[(0, (0, 2)), (2, (1, 1)), (3, (8, 3)), (6, (4, 2)), (8, (1, 2)), (10, (0, 1))]] get_rle(a, 1) -> [[(0, (0, 2))], [(3, (8, 3)), (6, (4, 2))], [(10, (0, 1))]] get_rle(a, 4) -> [[(0, (0, 2)), (2, (1, 1)), (3, (8, 3))], [(8, (1, 2)), (10, (0, 1))]] get_rle(a, 8) -> [[(0, (0, 2)), (2, (1, 1))], [(6, (4, 2)), (8, (1, 2)), (10, (0, 1))]]
  • 只是认为对一组使用相同的起始索引会减少嵌套,无论如何已经做到了。检查下面的答案或这个:inOneLine=lambda dat,n:[list(g) for k,g in itertools.groupby((zip((sum(tuple(zip(*((k,len(tuple(g))) ) for k,g in itertools.groupby(dat))))[1][:i]) for i in range(len(tuple(zip(*((k,len(tuple(g))) for k, g in itertools.groupby(dat))))[1]))) ,(zip(*tuple(zip(*((k,len(tuple(g)))) for k,g in itertools.groupby(dat) ))))))),lambda x:x[1][0]!=n) if k]

标签: python functional-programming list-comprehension arrays run-length-encoding


【解决方案1】:

只是为了说明如何,我强烈建议你不要使用这个

“优雅”的丑陋方式:

>>> data
[0, 0, 1, 8, 8, 8, 4, 4, 1, 0]
>>> def fromDataToSplitRLE(dat,n):
    RLE=[(k,len(tuple(g))) for k,g in itertools.groupby(dat)]
    tmp=tuple(zip(*RLE))
    return [list(g) for k,g in itertools.groupby((zip((sum(tmp[1][:i]) for i in range(len(tmp[1]))) ,(zip(*tmp)))),lambda x:x[1][0]!=n) if k]

>>> fromDataToSplitRLE(data,1)
[[(0, (0, 2))], [(3, (8, 3)), (6, (4, 2))], [(9, (0, 1))]]

【讨论】:

  • @aaronasterling:我理解错了。会改进的。
  • 我非常希望看到您通过列表理解来完成这项工作。
  • 请注意,这需要两次 groupby 调用。但是,它无需任何进一步处理即可正确拆分,而 aaron 则需要进一步传递 None。
  • @Kabie :您为此付出了很多努力,但您的函数比 aaron 的最终版本慢 3 倍,函数调用次数是 6 倍。我最初编写的代码执行的调用次数是原来的两倍,但花费的时间几乎相同。但是,基于您为此付出的巨大努力,我接受您的(您在上面的 cmets 中发布的那个)作为答案。
  • @PoorLuzer:永远不要编写像我评论中那样的函数。每个使用两次或更多次的返回值都应该存储在变量中,而不是再次调用该函数。我这样做只是为了将它写在一行中,而 aaronasterling 已经给出了适当的方式。
【解决方案2】:
import itertools

def get_rle(list_of_digits, split_on=None):
    count = 0
    rle = []
    active_group = []
    rle_app = rle.append
    for item, group in itertools.groupby(list_of_digits):
        L = len(list(group))
        if item == split_on:
            rle_app(active_group)
            active_group = []
        else:
            active_group.append((count, (item, L)))
        count += L

    rle_app(active_group)
    return rle

list_of_digits = map(int, '0 0 1 8 8 8 1 0'.split())
print get_rle(list_of_digits)
print get_rle(list_of_digits, 8)
print get_rle(list_of_digits, 1)

aaron@aaron-laptop:~/code/tmp$ python rle.py
[[(0, (0, 2)), (2, (1, 1)), (3, (8, 3)), (6, (1, 1)), (7, (0, 1))]]
[[(0, (0, 2)), (2, (1, 1))], [(6, (1, 1)), (7, (0, 1))]]
[[(0, (0, 2))], [(3, (8, 3))], [(7, (0, 1))]]

【讨论】:

  • 我已经写了这个(并且没有 None。注意我提到了 “可以省略空数组(拆分后)。”)这就是为什么我评论了 “(使用嵌套在其中的追加的 for 循环似乎更容易解决)” - 我正在寻找更快的东西 - 比如列表压缩。 想法?
  • @PoorLuzer。最后看我的笔记。我刚刚编辑了它。这将使它运行得更快。
  • 在(count, (item, L))中,count应该是开始索引,所以在if语句后加L
  • 您的最新版本满足了我的所有要求。做得好。我惊讶地发现你的最终版本比我原来的函数(这几乎是你第一次编写的函数)的调用次数多了 一半。我不知道这是否仅仅是由于本地绑定,但我发现没有其他区别(尽管看起来L = sum(1 for unused in group) 确实比L = len(list(group))! .
  • @PoorLuzer,取出 active_app.append 的本地绑定,看看是否不必为每个新组重新分配它是否会更快。我的想法(未经测试)是,如果组平均超过十个左右的元素,则制作本地绑定的成本将自行支付。如果长度小于那个值,那么这可能是一个糟糕的举动。我主要是为了表明可以做到的。
猜你喜欢
  • 2019-05-23
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-11-18
  • 1970-01-01
相关资源
最近更新 更多