【问题标题】:Python : Split list based on negative integersPython:基于负整数的拆分列表
【发布时间】:2017-01-26 00:56:28
【问题描述】:

我有一个列表说l = [1,5,8,-3,6,8,-3,2,-4,6,8]。我试图将它拆分为正整数的子列表,即上面的列表会给我[[1,5,8],[6,8],[2],[6,8]]。我尝试了以下方法:

l = [1,5,8,-3,6,8,-3,2,-4,6,8]
index = 0
def sublist(somelist):
    a = []
    for i in somelist:
        if i > 0:
            a.append(i)
        else:
            global index
            index += somelist.index(i)
            break
    return a

print sublist(l)

有了这个我可以得到第一个子列表([1,5,8])和3处的第一个负整数的索引号。现在,如果我再次运行我的函数并传递它l[index+1:],我无法获得下一个子列表并假设index 将更新为显示6。但是我不能,对于我的生活,我无法弄清楚如何在循环中运行函数或使用什么条件,以便我可以继续运行我的函数并给它l[index+1:] 其中index 是更新的,最近遇到的负整数的位置。任何帮助将不胜感激

【问题讨论】:

    标签: python


    【解决方案1】:

    您需要在此处跟踪两个级别的列表 - 包含子列表的大列表和子列表本身。启动一个大列表,启动一个子列表,并在i 为非负数时继续追加到当前子列表(顺便说一下,其中包括正数和 0)。当i 为负数时,将当前子列表追加到大列表并开始一个新的子列表。另请注意,您应该处理第一个元素为负数或最后一个元素不是负数的情况。

    l = [1,5,8,-3,6,8,-3,2,-4,6,8]
    
    def sublist(somelist):
        result = []
        a = []
        for i in somelist:
            if i > 0:
                a.append(i)
            else:
                if a: # make sure a has something in it
                    result.append(a)
                a = []
        if a: # if a is still accumulating elements
            result.append(a)
        return result
    

    结果:

    >>> sublist(l)
    [[1, 5, 8], [6, 8], [2], [6, 8]]
    

    【讨论】:

    • 我不确定我是否完全理解第二个if a: 声明
    • @letsc - 由于子列表 a 仅在遇到负数时附加到 result,因此省略第二个 if a: 将意味着输入列表末尾的正数得到添加到a,但a 永远不会添加到result
    • 哦!极好的。非常感谢!我接受了这个答案,因为它是第一次发布的,并且最接近我已经拥有的代码。其他 2 个答案也有效。
    • @letsc for container objects c (list, tuples, set, dict, etc) 当放置在像if c 这样的布尔上下文中时,相当于做if len(c)!=0
    【解决方案2】:

    由于somelist 永远不会改变,重新运行index 将始终获得元素的第一个实例的索引,而不是您刚刚到达的那个。我建议在循环时查看enumerate 以获取索引和元素,因此不需要调用索引。

    也就是说,您可以使用附带的电池来解决这个问题,使用itertools.groupby

    from itertools import groupby
    
    def sublist(somelist):
        return [list(g) for k, g in groupby(somelist, key=(0).__le__) if k]
    

    仍然值得通过你的代码来理解它,但上面的内容会很快而且相当简单。

    【讨论】:

    • 我会使用 lambda 函数,我认为这样更清楚
    • @Copperfield:当然,lambda x: x >= 0 是一种选择,但我原则上避免使用lambdas(我将它们限制在无法避免它们的情况下,所以当我使用它们时,我知道它很复杂),但我承认直接访问特殊的丰富比较方法是丑陋的。 key=functools.partial(operator.le, 0) 仍然可以提高 C 级内置函数的速度(lambdas 很慢)并使用带有完整文档的命名函数,尽管这涉及额外的导入。
    【解决方案3】:

    此代码使用了在此 URL 中找到的概念: Python list comprehension- "pop" result from original list?

    将此处找到的一个有趣概念应用于您的问题,以下是迄今为止其他人针对此问题发布的一些替代方法。两者都使用列表推导,并被注释以解释第二个选项与第一个选项的目的。作为我学习曲线的一部分,为我做了这个实验,但希望它也可以帮助你和这个线程上的其他人:

    这些的好处在于,如果您的输入列表非常大,您不必将内存消耗翻倍即可完成工作。当你缩小另一个时,你建立一个。

    此代码已在 Python 2.7 和 Python 3.6 上测试:

    o1 =  [1,5,8,-3,6,9,-4,2,-5,6,7,-7, 999, -43, -1, 888]    
                                    # modified version of poster's list
    o1b = [1,5,8,-3,6,8,-3,2,-4,6,8]    # poster's list
    
    o2 = [x for x in (o1.pop() for i in range(len(o1))) \
    if (lambda x: True if x < 0 else o1.insert(0, x))(x)]
    
    o2b = [x for x in (o1b.pop() for i in range(len(o1b))) \
    if (lambda x: True if x < 0 else o1b.insert(0, x))(x)]
    
    print(o1)
    print(o2)
    print("")
    
    print(o1b)
    print(o2b)
    

    它产生这样的结果集(在 iPython Jupyter Notebooks 上):

    [1, 5, 8, 6, 9, 2, 6, 7, 999, 888]
    [-1, -43, -7, -5, -4, -3]

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

    这是另一个版本,它也使用列表推导作为工作工具,但以更易读(我认为)和更容易使用不同数字列表进行测试的方式对代码进行了功能化。有些人可能更喜欢原始代码,因为它更短:

    p1 =  [1,5,8,-3,6,9,-4,2,-5,6,7,-7, 999, -43, -1, 888]    
                                    # modified version of poster's list
    p1b = [1,5,8,-3,6,8,-3,2,-4,6,8]    # poster's list
    
    def lst_mut_byNeg_mod(x, pLst):     # list mutation by neg nums module
        # this function only make sense in context of usage in 
        # split_pos_negs_in_list()
    
        if x < 0: return True
        else: 
            pLst.insert(0,x)
            return False
    
    def split_pos_negs_in_list(pLst):
        pLngth = len(pLst)              # reduces nesting of ((()))
        return [x for x in (pLst.pop() for i in range(pLngth)) \
                if lst_mut_byNeg_mod(x, pLst)]
    
    p2 = split_pos_negs_in_list(p1)
    print(p1)
    print(p2)
    print("")
    p2b = split_pos_negs_in_list(p1b)
    print(p1b)
    print(p2b)
    

    最后的想法: 之前提供的链接在评论线程中有很多想法:

    • 它建议 Google 搜索“python 布隆过滤器库” - 从性能的角度来看,这听起来很有希望,但我还没有研究过
    • 该线程上有一个帖子,有 554 人赞成,但它至少有 4 个 cmets 解释了它可能有什么问题。在探索选项时,建议扫描评论线索,而不仅仅是查看获得最多选票的内容。针对此类情况提出了许多选项。

    【讨论】:

      【解决方案4】:

      只是为了好玩,您也可以使用re 来作为一个班轮。

      l = [1,5,8,-3,6,8,-3,2,-4,6,8]
      print map(lambda x: map(int,x.split(",")), re.findall(r"(?<=[,\[])\s*\d+(?:,\s*\d+)*(?=,\s*-\d+|\])", str(l)))
      

      输出:[[1, 5, 8], [6, 8], [2], [6, 8]]

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 2012-03-21
        • 2019-07-14
        • 1970-01-01
        • 2016-01-08
        • 1970-01-01
        • 1970-01-01
        • 2016-06-15
        • 2016-08-25
        相关资源
        最近更新 更多