0

リストに入れられたオブジェクトのすべてのプロパティに対してハッシュされたインデックス (辞書) を作成するリストを Python で作成する最良の方法を探しています。

>>> foo = IndexingList([{ 'id': 1, 'name': 'cat' }, { 'id': 2, 'name': 'dog' }])
>>> foo[0]
{'id': 1, 'name': 'cat'}

>>> foo.findall('id', 2)
[{'id': 2, 'name': 'dog'}]

>>> foo += {'id': 3, 'name': 'dog'}
>>> foo.findall('name', 'dog')
[{'id': 2, 'name': 'dog'}, {'id': 3, 'name': 'dog'}]

IndexingList のデータ構造は次のようになると思います。

{
    'items': [
        { 'id': 1, 'name': 'cat' }, 
        { 'id': 2, 'name': 'dog' }
    ],
    'indexes': {
        'id': {
            1: [{ 'id': 1, 'name': 'cat' }],
            2: [{ 'id': 2, 'name': 'dog' }]
        },
        'name': {
            'cat': [{ 'id': 1, 'name': 'cat' }],
            'dog': [
                { 'id': 2, 'name': 'dog' },
                { 'id': 3, 'name': 'dog' }
            ]
        }
    }
}

「インデックス」ノード内のオブジェクトは、「アイテム」内の同じオブジェクトを参照します。

それ自体がオブジェクトであるプロパティ値は、 str(property) を使用して「インデックス」に固執するものを取得することにより、一意のインデックスキーを受け取ることができると思います。

4

2 に答える 2

3

これは、いくつかの を使用して実際に行うのは非常に簡単collections.defaultdict()ですが、これを頻繁に使用する場合は、実際のデータベースを使用することを検討してください。

from collections import defaultdict
from functools import partial

class IndexingList:
    def __init__(self, items):
        self.items = []
        self.indices = defaultdict(partial(defaultdict, list))
        self.extend(items)

    def append(self, item):
        try:
            for index, value in item.items():
                self.indices[index][value].append(item)
        except AttributeError as e:
            raise ValueError("All children of an IndexingList must be "
                             "dict-like. '{0}' is not.".format(item)) from e
        self.items.append(item)

    def extend(self, iterable):
        for item in iterable:
            self.append(item)

    def __iadd__(self, other):
        self.extend(other)
        return self

    def __getitem__(self, item):
        return self.items[item]

    def __setitem__(self, item, value):
        self.items[item] = value

    def __delitem__(self, item):
        del self.items[item]
        for index, value in item.items():
            self.indices[index][value].remove(item)

    def find_all(self, index, value):
        return self.indices[index][value]

    def __repr__(self):
        return repr(self.items)

次のように使用します。

>>> foo = IndexingList([{ 'id': 1, 'name': 'cat' }, { 'id': 2, 'name': 'dog' }])
>>> foo[0]
{'id': 1, 'name': 'cat'}
>>> foo.find_all("id", 2)
[{'id': 2, 'name': 'dog'}]
>>> foo += [{'id': 3, 'name': 'dog'}]
>>> foo.find_all('name', 'dog')
[{'id': 2, 'name': 'dog'}, {'id': 3, 'name': 'dog'}]
于 2012-10-28T17:26:13.423 に答える
0

Lattyware は本当に優れたソリューションを提供していると言わざるを得ません。一意のアイテムにインデックスを付けるときは単純なワンライナーであるため、私自身の簡単で汚いアプローチを引き続き提供します。適切なラッパー コンテナーを作成する代わりに、特定の列にインデックスを作成することがあります。

my_list = [('aap', 123), ('noot', 234), ('mies', 345), ('mies', 456)]

その列のキーが一意であり、リストに新しい要素を追加したり、インデックスを作成した値を変更したりしない場合は、次を使用できます。

def mk_unique_index(data, col):
  g = ((elem[col], elem) for elem in data)
  return dict(g)

したがって、次のように使用できます。

>>> idx = mk_unique_index(my_list, 1)
>>> idx[123]
('aap', 123)

ただし、0 番目の列にインデックスを付けたい場合は、defaultdict を使用する必要があります。

from collections import defaultdict
def mk_index(data, col):
  d = defaultdict(list)
  for elem in data:
    d[elem[col]].append(elem)
  return d

使用法:

>>> idx = mk_index(my_list, 0)
>>> idx['mies']
[('mies', 345), ('mies', 456)]

タプルの代わりに辞書や名前付きタプルを使用している場合 (すべての要素にインデックスを作成するフィールドがある場合)、列のフィールド名を指定するだけで済みます。もちろん、メモリ内の一時的なsqliteデータベースを使用することもできます。

于 2014-06-01T18:04:12.807 に答える