匹配基于属性的对象列表,并识别不兼容的对象

时间:2018-03-26 17:12:56

标签: python list-comprehension list-comparison

对于我正在处理的应用程序,我正在搜索文件目录,并希望找到匹配的文件对来执行进一步的分析。

在这种情况下,一对被定义为在某些属性子集上匹配,但在某些其他属性上有所不同。

作为错误处理/警告的一部分,我想识别找到的无法比较的任何文件,"即期望的"合作伙伴"在这对中找不到。

我有一类对象来存储结构化属性信息,当我读取目录中的文件时,我将每个找到的文件存储为这些对象列表中的元素。

这是一个愚蠢的简单例子

class glove(object):
    def __init__(self, size, color, is_right):
        self.size = size
        self.color = color
        self.is_right = is_right

    def __repr__(self):
        if self.is_right:
            hand = "right"
        else:
            hand = "left"
        s = "{} {} {}".format(self.size, self.color, hand)
        return(s)


gloves = [glove('med', 'black', False),
          glove('med', 'black', True),
          glove('lg', 'black', False),
          glove('lg', 'black', True),
          glove('med', 'brown', False),
          glove('med', 'brown', True),
          glove('lg', 'blue', False),
          glove('med', 'tan', False)]

left_gloves = [x for x in gloves if not x.is_right]
right_gloves = [x for x in gloves if x.is_right]

我们假设列表中没有重复的元素,让我们定义一个"对"作为两个glove个匹配glove.sizeglove.colorglove.is_right值不同的对象(即一个是右,一个是左)。

现在我想识别不完整的对(可能是leftovers的列表,以便我可以错误或警告,例如"没有找到左手蓝色手套"&# 34;没有找到左手棕褐色手套。"

我看过answers教授如何识别物品"失踪"从列表对,但我的应用程序有一些复杂性,我无法弄清楚如何解决:链接对象的属性,以及链接对象的多个属性。

我认为for循环和列表理解可以实现一些东西,但我无法弄清楚如何将它们连接在一起。

2 个答案:

答案 0 :(得分:2)

如果你可以为你的类实现相等/哈希,这很容易:

[lg blue left, med tan left]

输出:

class glove(object):
    def __init__(self, size, color, is_right):
        self.size = size
        self.color = color
        self.is_right = is_right

    def __repr__(self):
        if self.is_right:
            hand = "right"
        else:
            hand = "left"
        s = "{} {} {}".format(self.size, self.color, hand)
        return(s)


gloves = [glove('med', 'black', False),
          glove('med', 'black', True),
          glove('lg', 'black', False),
          glove('lg', 'black', True),
          glove('med', 'brown', False),
          glove('med', 'brown', True),
          glove('lg', 'blue', False),
          glove('med', 'tan', False)]

# With plain dict
glove_search = {}
for g in gloves:
    glove_search.setdefault(g.size, {}).setdefault(g.color, {})[g.is_right] = True
unpaired = [g for g in gloves
            if not glove_search.get(g.size, {}).get(g.color, {}).get(not g.is_right, False)]

# Or, more idiomatically, with defaultdict
from collections import defaultdict
glove_search = defaultdict(lambda: defaultdict(lambda: defaultdict(bool)))
for g in gloves:
    glove_search[g.size][g.color][g.is_right] = True
unpaired = [g for g in gloves if not glove_search[g.size][g.color][not g.is_right]]

print(unpaired)

你也可以考虑使用namedtuple,它实际上是为你做的。

这是一个不需要实现equals和hash,也不需要创建新对象的替代方法:

[lg blue left, med tan left]

输出:

foo_AUDIT

答案 1 :(得分:2)

不允许重复,问题相对简单。 连接您的标识符:

self.ID = self.size + " " + self.color

仅在ID上构建左/右子集。

left  = {g.ID for g in gloves if not g.is_right)
right = {g.ID for g in gloves if     g.is_right)

unmatched_left  = left - right
unmatched_right = right - left

现在,只需反转关键过程即可获得手套对象:

unmatched = [g for g in glove_set \
             if g.ID in unmatched_left + unmatched_right]