开发者

Python list, lookup object name, efficiency advice

开发者 https://www.devze.com 2023-01-08 12:31 出处:网络
Suppose I have the following object: class Foo(object): def __init__(self, name=None): self.name = name def __repr__(self):

Suppose I have the following object:

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

  def __repr__(self):
    return self.name

And a list containing multiple instances, such as:

list = [Foo(name='alice'), Foo(name='bob'), Foo(name='charlie')]

If I want to find an object with a given name, I could use the following:

def get_by_name(name, list):
  return [foo for foo in list if foo.name == name][-1]

Which would obviously mean:

print get_by_name('alice', list)
>> alice

However, is there a more efficient data structure or method for retrieving such objects? In reality, the object names are only known at runtime and could in theory change throughout the lifecycle of the object.

Any advice?

UPDATE:

Thanks to Matt Joiners answer, I have updated it to support multiple Foo's with the same name:

class Foo(object):
    _all_names = {}    
    def __init__(self, name=None):
        self._name = None
        self.name = name        
    @property
    def name(self):
        return self._name        
    @name.setter
    def name(self, name):
        if self._name is not None:
            self._all_names[self._name].remove(self)
        self._name = name
        if name is not None:
            self._all_names.setdefault(name, []).append(self)
    @classmethod
    def get_by_name(cls, name):
        return cls._all_names[name]        
    def __repr__(self):
        return "{0}".format(self.name)

l = [Foo("alice"), Foo("bob"), Foo('alice'), Foo('charlie')]
开发者_StackOverflow中文版print Foo.get_by_name("alice")
print Foo.get_by_name("charlie")

Any comments on this approach?


Try this for size:

class Foo(object):
    _all_names = {}
    def __init__(self, name=None):
        self.name = name
    @property
    def name(self):
        return self._name
    @name.setter
    def name(self, name):
        self._name = name
        self._all_names[name] = self
    @classmethod
    def get_by_name(cls, name):
        return cls._all_names[name]
    def __str__(self):
        return "Foo({0})".format(self.name)

a = Foo("alice")
b = Foo("bob")
print Foo.get_by_name("alice")

Keep in mind it's kept minimal to convey the idea, there are many tweaks and checks you can make here and there.


The situation is a little confusing.

You're going to be searching for this object in a list which is a linear data structure. The only way to look for something is by going through it one by one. This makes the time grow linearly with the length of the list. So that is where your speed issue is.

The way to get some speed gains is to use some kind of hashing scheme to keep your objects directly indexable by the key you're interested in (in your case, name). This will allow you to look up an object in a way similar to dictionary key lookup. It's a constant time operation. This is basically what Matt's answer does. He's keeping an "index" as a class level structure so that you can look things up using hashing rather than by walking a list.

0

精彩评论

暂无评论...
验证码 换一张
取 消