0

我有一个具有 3 个属性 a、b 和 c 的测试类。已经创建了 3 个类的实例,并为属性设置了适当的值,假设 'a' 属性始终是唯一的,并且当两个具有相同 'b' 值的对象将始终具有相同的 'c' 值时。如果看到此类对象,则该对象的属性“c”的显示将被省略。

class test():
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __repr__(self):
        return 'test(%s, %s, %s)' % (self.a, self.b, self.c)


test1 = test("1", "abc", "def")
test2 = test("2", "yyy", "xxy")
test3 = test("3", "yyy", "xxy")

objList = [test1, test2, test3]

#takes out duplicate objects
new_list = [next(obj) for i, obj in
            groupby(sorted(objList, key=lambda test: test.a), lambda test: test.c)]
print(new_list)

上面的代码让我输出如下。

[测试(1, abc, def), 测试(2, yyy, xxy)]

预期的输出是从对象中仅省略属性 c。

[test(1, abc, def), test(2, yyy, xxy),test(3, yyy)]

请帮忙!

4

1 回答 1

0

更新了 REPR

为了能够更改类正在打印的内容,您必须能够更改repr方法。主要是因为呈现的内容有点过于狭隘。相反,如果类如下,那么这是可能的:

class test():
    def __init__(self, a, b, c):
        self.a = a
        self.b = b
        self.c = c

    def __repr__(self):
      expr = []
      if self.a:
        expr.append(self.a)
      if self.b:
        expr.append(self.b)
      if self.c:
        expr.append(self.c)

      return 'test(%s)' % (', '.join(expr))

最大的障碍是我们需要对显示的内容进行一些控制,因此我们需要更改repr方法。或者,您可以通过利用str方法并在打印之前转换为字符串来生成相同的结果。

类型无关的删除重复功能

由于我不知道您是确切的用例,并且想制作与所有类型的问题相关的东西,因此我制作了以下功能。它将允许您指定相等条件、满足条件时执行的操作以及如何对列表进行排序。

(默认是检查后续值对象是否相等,如果相等则不包括结果列表中的第二个。)

def remove_dups(old_list, 
                condition=lambda a, b: a == b, 
                remove_func=lambda x, y: None, 
                sort_key=None):
  """
    Returns a new list that has duplicates removed from `old_list`

    #Arguments
    old_list: list to have duplicates discarded
    condition: test condition between previous and next obj to test equality.
    remove_func: what to add to the list if the condition is met. If `None` is returned
      then no value is added to the `new_list`
    sort_key: how to sort the `old_list`.
  """


  old_list = sorted(old_list, key=sort_key)
  comparitor = old_list[0] #used to compare previous and current obj
  new_list = [comparitor]
  for i, obj in enumerate(old_list[1:]):
    #if previous object and current obj are the same
    if condition(comparitor, obj):

      #run removal function
      if remove_func:
        new_value = remove_func(comparitor, obj)
      else:
        new_value = None

    else: #then objects are different, add the new one
      new_value = obj

    if new_value is not None:
      new_list.append(new_value)

    comparitor = obj
    new_value = None

  return new_list

您的案例(示例)

我们可以在您的情况下使用它,如下所示

test1 = test("1", "abc", "def")
test2 = test("2", "yyy", "xxy")
test3 = test("3", "yyy", "xxy")

objList = [test1, test2, test3]

#in lambda functions `a` corresponds to previous object in list,  
#`b` refers to currently observed object
new_list = remove_dups(objList,
            condition=lambda a, b: a.b == b.b, #if a.b and b.b the same
            remove_func=(lambda a, b: test(b.a, b.b, None)), #then set b.c = None
            sort_key=lambda obj: (obj.a, obj.b, obj.c)
          )

print(new_list) # [test(1, abc, def), test(2, yyy, xxy), test(3, yyy)]

编辑

如果您想在不编辑repr方法的情况下执行此操作,那么您可以执行一些特殊的打印语句,new_list而不是显式尝试打印测试对象。

例子:

objList = [test1, test2, test3]

#in lambda functions `a` corresponds to previous object in list,  
#`b` refers to currently observed object
new_list = remove_dups(objList,
            condition=lambda a, b: a.b == b.b, #if a.b and b.b the same
            remove_func=(lambda a, b: test(b.a, b.b, None)), #then set b.c = None
            sort_key=lambda obj: (obj.a, obj.b, obj.c)
          )

exprs = []
for test in new_list:
  expr = []
  if test.a:
    expr.append(test.a)
  if test.b:
    expr.append(test.b)
  if test.c:
    expr.append(test.c)

  exprs.append('test(%s)' % (', '.join(expr)))

print(exprs) # [test(1, abc, def), test(2, yyy, xxy), test(3, yyy)]
于 2020-05-21T13:40:36.710 回答