Python 从属性等于某个值的列表中查找对象,并获取后面的下一个对象

Python 从属性等于某个值的列表中查找对象,并获取后面的下一个对象,python,python-2.7,itertools,Python,Python 2.7,Itertools,我能够找到一个属性等于某个值的对象。但是我也希望从列表中获取之后的对象,并且如果找到的对象是列表中的最后一个,那么之后的下一个对象应该是第一个对象。比如: from pprint import pprint class User(object): def __init__(self, name): self.name = name users = [] users.append(User("Peter")) users.append(User("James")) us

我能够找到一个属性等于某个值的对象。但是我也希望从列表中获取之后的对象,并且如果找到的对象是列表中的最后一个,那么之后的下一个对象应该是第一个对象。比如:

from pprint import pprint

class User(object):
    def __init__(self, name):
        self.name = name

users = []
users.append(User("Peter"))
users.append(User("James"))
users.append(User("John"))

#   find object that has attribute name equal to James
pprint(vars([user for user in users if user.name == "James"][0]))
pprint行的输出打印:

{'name': 'James'}
这是正确的

我想问你如何获得詹姆斯之后的下一个对象,以及我是否会搜索约翰约翰之后的下一个对象应该返回彼得。建议

我还尝试使用itertools,但如果找到的元素是最后一个,则无法获取下一个元素:

from itertools import enumerate
_i = next(i for i, user in enumerate(users) if (user.name == "John"))
print users[_i + 1] #this is not working 

我可以在操作[_I+1]之前添加if条件来更改计数器,但我想知道是否有更平滑的解决方案?

要处理最后一个元素,可以使用modulo:index%lenusers

这里有一个方法:

def find_after_name(users, name):
    for i, user in enumerate(users):
        if user.name == name:
            return users[(i+1) % len(users)]
另一种选择是使用列表的移位副本压缩列表。deque.rotate可用于此类换档:

from collections import deque
def find_after_name(users, name):
    users2 = deque(users)
    users2.rotate(-1)
    for user1, user2 in zip(users1, users2):
        if user1.name == name:
            return user2

要处理最后一个元素,可以使用modulo:index%lenusers

这里有一个方法:

def find_after_name(users, name):
    for i, user in enumerate(users):
        if user.name == name:
            return users[(i+1) % len(users)]
另一种选择是使用列表的移位副本压缩列表。deque.rotate可用于此类换档:

from collections import deque
def find_after_name(users, name):
    users2 = deque(users)
    users2.rotate(-1)
    for user1, user2 in zip(users1, users2):
        if user1.name == name:
            return user2

既然您选择使用OOP,为什么不实现从内置列表类继承的UserList类呢

class User(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return repr(self)

    def __repr__(self):
        return "User('{0}')".format(self.name)


class UserList(list):
    def find(self, name):
        for k, user in enumerate(self):
            if user.name == name:
                return k, user

    def next_to(self, name):
        """get user next to the one of name (e.g. 'James')"""
        index, user = self.find(name)
        next_to_index = self.get_next_to_index(index)
        return self[next_to_index]

    def get_next_to_index(self, index):
        next_to_index = index + 1
        if next_to_index == len(self):
            # meaning index is already the last element, need to reset index
            next_to_index = 0
        return next_to_index


users = UserList()
users.append(User("Peter"))
users.append(User("James"))
users.append(User("John"))

print users.find('James')
print users.next_to('James')
print users.next_to('John')
输出:

(1, User('James'))
User('John')
User('Peter')

既然您选择使用OOP,为什么不实现从内置列表类继承的UserList类呢

class User(object):
    def __init__(self, name):
        self.name = name

    def __str__(self):
        return repr(self)

    def __repr__(self):
        return "User('{0}')".format(self.name)


class UserList(list):
    def find(self, name):
        for k, user in enumerate(self):
            if user.name == name:
                return k, user

    def next_to(self, name):
        """get user next to the one of name (e.g. 'James')"""
        index, user = self.find(name)
        next_to_index = self.get_next_to_index(index)
        return self[next_to_index]

    def get_next_to_index(self, index):
        next_to_index = index + 1
        if next_to_index == len(self):
            # meaning index is already the last element, need to reset index
            next_to_index = 0
        return next_to_index


users = UserList()
users.append(User("Peter"))
users.append(User("James"))
users.append(User("John"))

print users.find('James')
print users.next_to('James')
print users.next_to('John')
输出:

(1, User('James'))
User('John')
User('Peter')

对于kicks,我想看看是否有itertools解决方案:

from itertools import dropwhile
def find_after_name(users, name):
    for i, _ in dropwhile(lambda eu: eu[1].name != name, enumerate(users)):
        return users[(i+1) % len(users)]
注意:确实应该有一个list.indexvalue,key=None方法,其中key类似于list.sort的key参数。然后你可以这样做:

index = users.index("John", key=lambda u: u.name)

对于kicks,我想看看是否有itertools解决方案:

from itertools import dropwhile
def find_after_name(users, name):
    for i, _ in dropwhile(lambda eu: eu[1].name != name, enumerate(users)):
        return users[(i+1) % len(users)]
注意:确实应该有一个list.indexvalue,key=None方法,其中key类似于list.sort的key参数。然后你可以这样做:

index = users.index("John", key=lambda u: u.name)

解决方案扩展列表类:

class extended_list(list):
    def index(self, value, key=None):
        if key is None:
            return super().index(self, value)
        try:
            return next(i for i,o in enumerate(self) if value == key(o))
        except StopIteration:
            raise ValueError("{} is not in list".format(repr(value)))


def find_after_name(users, name):
    i = extended_list(users).index(name, key=lambda u: u.name)
    return users[(i+1) % len(users)]

解决方案扩展列表类:

class extended_list(list):
    def index(self, value, key=None):
        if key is None:
            return super().index(self, value)
        try:
            return next(i for i,o in enumerate(self) if value == key(o))
        except StopIteration:
            raise ValueError("{} is not in list".format(repr(value)))


def find_after_name(users, name):
    i = extended_list(users).index(name, key=lambda u: u.name)
    return users[(i+1) % len(users)]


您缺少itertools示例第二行的结束语。无关?@Celeo类型错误,谢谢!您缺少itertools示例第二行的结束语。无关?@Celeo类型错误,谢谢!需要返回错误的方法:ValueError,如list.index或returnNone@Harvey如果循环为空,则隐式返回Noneexhausted@shx2你能用一两句话解释一下这个表达式在Pythoni+1%中是如何解释的吗?Do deque and deque.rotate将修改后的数据存储到新的内存空间,就像在实际问题中一样。我必须以这种方式处理相当多的数据,这不是最有效的方式,还是我错了?@shx2:谢谢你提醒我不要这样做。此外,我还添加了一个更具pythonic功能的解决方案,避免了额外的存储。它使用itertools.dropwhile作为索引方法。只需返回第一个值为user的元组,如:return user,users[i+1%lenusers]需要返回错误的方法:ValueError,如list.index或returnNone@Harvey如果循环为空,则隐式返回Noneexhausted@shx2你能用一两句话解释一下这个表达式在Pythoni+1%中是如何解释的吗?Do deque and deque.rotate将修改后的数据存储到新的内存空间,就像在实际问题中一样。我必须以这种方式处理相当多的数据,这不是最有效的方式,还是我错了?@shx2:谢谢你提醒我不要这样做。此外,我还添加了一个更具pythonic功能的解决方案,避免了额外的存储。它使用itertools.dropwhile作为索引方法。只需返回一个元组,其中第一个值是user,比如:return user,users[i+1%lenusers]我还想使用itertools中的cycle,但是有些东西没有按我计划的那样工作。@avstenit:python IRC频道上的一些人指出,这是正确的方法:enumeratelist中I,o的nexti if value==keyoI也在考虑使用类似于itertools中的cycle的东西,但是有些东西没有按我计划的那样工作。@avstenit:python IRC频道上的一些人指出这是正确的方法:enumeratelist中I,o的nexti如果value==keyoWell初始数据是矩阵形式,然后我也用它来构建对象,真正的问题是关于类节点而不是类用户——它只是用于一个简单的例子。所以我必须决定该走哪条路。我们的目标不是向类Userok添加太多额外的方法,您的描述对我来说不是很清楚,但很好,您似乎已经做出了决定。初始数据是矩阵形式的,然后我也从中构建对象。真正的问题是关于类节点而不是类用户-它仅用于简单的示例。所以我必须决定该走哪条路。我们的目标不是向类Userok添加太多额外的方法,我对您的描述不是很清楚,但很好,您似乎已经做出了决定。