【问题标题】:select elements in a list by the occurrence of zeros in python通过在python中出现零来选择列表中的元素
【发布时间】:2016-08-02 20:45:03
【问题描述】:

给定一个二维列表:

X = [ [a,2], [b,12], [c,6], [d,0], [e,2], [f,0], [g,0], [h,12], [i,18] ]

我需要得到一个二维列表,它将所有子列表分组,在X[1] 列中用零分隔。我的意思是,我需要选择:

Y = [ [[a,2],[b,12],[c,6]], [[e,2]], [[h,12],[i,18]] ]

ang 仅获取对应的X[0] 条目的列表:

Y = [ [a, b, c], [e], [h, i] ]

我已经问过一个类似的问题,即根据列表中出现的零来选择列表中的元素,但它是一维列表。使用 itertools,我尝试了类似的方法:

Z = [list(v) for k, v in itertools.groupby(X[:,1], lambda x: x == 0) if not k] 

我使用X[:,1] 作用于列表的X[1] 部分,因为选择作用于它。但它显然给了我列表中的X[1] 部分:

Z = [[2, 12, 6], [2], [12, 18]]

但我需要X[0] 列...如何在多维列表上使用 itertools?提前致谢。

【问题讨论】:

  • 问题不够清楚。你的输入是什么,预期的输出是什么? '用零分隔'?我在您的示例中没有看到零。尝试理解了两分钟,失败了
  • X 中的输入和所需的输出是Y(第二个)。零在 X 列表 ([d,0], [f,0], [g,0]) 的 X[1] 部分。

标签: python list selection itertools zero


【解决方案1】:

我相信这会起作用:

[map(lambda a:a[0],list(v)) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k]

更多解释:

你想根据列表中每个项目的第二个值对 X 进行分组所以你需要这样做:
itertools.groupby(X, lambda x: x[1] == 0)

[list(v) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k] 将创建这样的二维列表:
[[['a', 2], ['b', 12], ['c', 6]], [['e', 2]], [['h', 12], ['i', 18]]] 所以你需要操作列表中的每个项目并且只获取第二个索引,这可以通过map 函数来完成:

[map(lambda a:a[0],list(v)) for k, v in itertools.groupby(X, lambda x: x[1] == 0) if not k]

【讨论】:

  • 这是一个非常丑陋且不透明的 itertools、列表理解、函数式成语内置函数和 lambda 表达式的组合。我知道你是对的,但我不能凭良心赞成这个代码,除非你把它分成几行并让它可读。如果您不尝试将代码塞进一行,那么您的代码不需要太多解释。只需使用描述性名称即可。
  • 我不认为那些正在做他期望的事情,这是Y = [ [[a,2],[b,12],[c,6]], [[e,2]], [[h,12],[i,18]] ]
  • @machineyearning 我试图找到一个与他试图做的尽可能相似的解决方案,如果我能找到一个,也许我会添加更好的解决方案
  • @DanielSanchez Y 只是解决问题的一步,他写它是为了解释他在寻找什么。
  • 嗯,谢谢你的提示。基本上,我弄错的是itertools.groupby(X, lambda x: x[1] == 0) 中的x[1] 条件。 map 对我不起作用,但是好的,现在我得到一个 3D 列表,之后我可以选择我需要的条目。
【解决方案2】:

您可以使用迭代器定义自己的拆分器:

def splitter(L):
    group = []
    res = []
    for i in iter(L):
        if i[1]:
            group.append(i[0])
        if not i[1] and len(group):
            res.append(group)
            group = []
    if len(group):
        res.append(group)
    return res

#In [62]: splitter(X)
#Out[62]: [['a', 'b', 'c'], ['e'], ['h', 'i']]

如果您使用字符,这是一种方法 - 尽管我更喜欢拆分器来解决您的特定问题:

[list(u) for u in ''.join([i[0] if i[1] else '|' for i in X]).split("|") if u]
#[['a', 'b', 'c'], ['e'], ['h', 'i']]

我还会通过一个小技巧改进/缩短@Elisha 的答案:

from itertools import groupby

[list(zip(*v)[0]) for k, v in groupby(X, lambda x: x[1] == 0) if not k]

【讨论】:

  • 最短的!=最好的。这是不需要 cmets 且易于理解的代码。但是为什么iter(L) 普通L 会做呢?个人更喜欢在测试中使用len(group) != 0:虽然功能相同,但更易于阅读。
  • iter(L) 是一种反射,因为我通常使用迭代器。我认为len(group)if i[1] 更明确 :) 但是是的,你是对的,可以明确提到条件。
【解决方案3】:

我会这样做:

X = [ ['a',2], ['b',12], ['c',6], ['d',0], ['e',2], ['f',0], ['g',0], ['h',12], ['i',18] ]
ind = [-1] + [i for i in range(n) if X[i][1]==0] + [len(X)] # found the indices of the "zero" lists
Y = [X[ind[i]+1:ind[i+1]] for i in range(len(ind)-1)] # choose the items between those indices
Y = [[x[0] for x in list] for list in Y] # take only X[0]
Y
#output
[['a', 'b', 'c'], ['e'], [], ['h', 'i']]

它只是找到“零”索引,然后使用切片来获取正确的列表列表。

当然你可以删除最后的空列表。

【讨论】:

    猜你喜欢
    • 2014-07-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-11-22
    • 1970-01-01
    • 2022-08-19
    • 2017-01-02
    相关资源
    最近更新 更多