使用条件

时间:2016-07-21 21:40:14

标签: python collections

我有一组对象,我想使用lambda表达式或某种条件删除集合的值。

我会这样做:

def pop(container, cond):
    value = None
    removed = False

    for x in container:
        if cond(x):
            value = x
            removed = True
            container.remove(x)
            break

     if not removed:
         raise Exception('No value to pop')

     return value

示例用例是:

compare_object = {"price": 100, "quantity": 1, "product_id": 2}
objs = set([....])

def comparison(obj):
    def wrap(obj2):
        return (
            obj2['price'] == obj['price'] and
            obj2['quantity'] == obj['quantity'] and
            obj2['product_id'] == obj['product_id']
        )


similar_obj = pop(objs, comparison(compare_object))

这样,我们可以从一个集合中获得一个类似的对象,因此在调用该方法后,该集合将被减少。

我想知道是否有一种更简单的方法可以使用python中已有的实际数据结构来实现这一点,而不是在大型集合上进行循环,这在大集合上可能很昂贵?

3 个答案:

答案 0 :(得分:2)

您可以从该条件创建for(或者对于Python 2 filter)而不是复杂的itertools.ifilter循环,并从该过滤器中删除next元素。

def pop(container, cond):
    try:
        value = next(filter(cond, container))
        container.remove(value)
        return value
    except StopIteration:
        raise Exception("No Value to pop")

示例:

>>> lst = [1,2,3,4,5]
>>> cond = lambda x: x % 2 == 0
>>> pop(lst, cond)
2
>>> pop(lst, cond)
4
>>> pop(lst, cond)
Exception: No Value to pop
>>> lst
[1, 3, 5]

或者您可以通过立即返回找到的值来简化您的功能:

def pop(container, cond):
    for x in container:
        if cond(x):
            container.remove(x)
            return x
    raise Exception('No value to pop')

答案 1 :(得分:1)

您的pop()方法基本上与已构建的filter()重复,并在生成的next()对象上调用filter。您可以将代码简化为:

compare_object = {"price": 100, "quantity": 1, "product_id": 2}
objs = set([....])

def comparison(obj):
    def wrap(obj2):
        return (
            obj2['price'] == obj['price'] and
            obj2['quantity'] == obj['quantity'] and
            obj2['product_id'] == obj['product_id']
        )

similar_obj = next(filter(comparison(compare_object), objs))

如果没有匹配,这将引发StopIteration

至于性能:如果你有一个集合,根据定义是无序的,并且你的条件必须检查每个条目,那么就无法迭代所有元素。但由于您只检索第一次出现,因此几乎不需要遍历整个集合。由于filter()懒惰地评估其结果,因此它的行为方式相同,只会迭代整个集合,直到找到第一个匹配。

答案 2 :(得分:0)

由于某些原因,我决定采用defaultdict变体。而不是使用set。我只是将数据存储在带有列表的defaultdict中。

设置容器:

container = defaultdict(list)
for exp_line in exp_lines:
    container[(
        exp_line.unit_amount,
        exp_line.unit_quantity,
        exp_line.product_id,
        exp_line.uom_id
    )].append(exp_line)

从容器弹出:

obj = container[(
    -(aal.amount/aal.unit_amount),
    aal.unit_amount,
    aal.product_id,
    aal.product_uom_id
)].pop()

我用这种方法看到的唯一缺点是,没有简单的方法可以知道容器是否为空。但是尝试从空列表弹出将引发异常,就像预期的那样,数据实际上已从容器中删除。

由于条件相当严格,因此#34;就好像我使用单一条件一样,这样就简单得多了。但如果我不得不使用" custom"无法进行哈希处理的密钥。其他答案用" next / filter"我猜是一个更好的工具。

确实没有算法。