说我有这样的事情:
from collections import namedtuple
Obj = namedtuple('Obj', ['x', 'y'])
items = [Obj(1,1), Obj(1,2), Obj(1,3), Obj(1,3), Obj(1,3)]
对于特定属性,count
有没有办法?我希望你能做一些像:
test = [ obj for obj in items if items.count(obj.y) > 1 ]
然而,这给出了一个空列表,而不是包含元素Obj(1,3)
的列表。有没有人有一线解决方案?
答案 0 :(得分:6)
分别创建计数映射;使用collections.Counter()
使这很容易:
from collections import Counter
y_counts = Counter(obj.y for obj in items)
test = [obj for obj in items if y_counts[obj.y] > 1]
演示:
>>> from collections import Counter
>>> from collections import namedtuple
>>> Obj = namedtuple('Obj', ['x', 'y'])
>>> items = [Obj(1,1), Obj(1,2), Obj(1,3), Obj(1,3), Obj(1,3)]
>>> y_counts = Counter(obj.y for obj in items)
>>> [obj for obj in items if y_counts[obj.y] > 1]
[Obj(x=1, y=3), Obj(x=1, y=3), Obj(x=1, y=3)]
答案 1 :(得分:1)
要从obj
中获取items
所有对象obj.y
,其中test = [obj for obj in items if sum(1 for o in items if o.y == obj.y) > 1]
在列表中出现多次,在一行中:
[Obj(x=1, y=3), Obj(x=1, y=3), Obj(x=1, y=3)]
这给了我:
O(n**2)
但请注意,此“算法”为collections.defaultdict(list)
,效率不高。相反,创建一个字典(您可以使用d = {}
for obj in items:
if obj.y not in d:
d[obj.y] = []
d[obj.y].append(obj)
)简化:
test = []
for v in d.values():
if len(v) > 1:
test.extend(v)
然后获取长于1的值:
{{1}}
答案 2 :(得分:0)
如果我理解你要做的事情,那就收集具有相同y值的对象数量的项目
一种简单的方法是,
from collections import Counter
counter = Counter(items)
然后,你需要的测试,
test = [obj for obj, count in counter.items() if count > 1]
答案 3 :(得分:0)
仅供记录,因为Martijn Pieters answer显然更好更容易。问题在于count
依赖于__eq__
函数,因此您可以覆盖它以实现结果。
from collections import namedtuple
class CustomTuple(namedtuple('Obj', ['x', 'y'])):
def __eq__(self, other):
return self.y == other.y
然后你可以使用:
items = [CustomTuple(1,1), CustomTuple(1,2), CustomTuple(1,3), CustomTuple(1,3), CustomTuple(1,3)]
print [obj for obj in items if items.count(obj) > 1]
或直接:
[obj for obj, count in Counter(items).iteritems() if count > 1]
基本上,您只是说CustomTuple('value', y)
总是等于CustomTuple('another_value', y).
所有y
。