from signac.core.search_engine import DocumentSearchEngine


def _index(docs):
    return {doc['_id']: doc for doc in docs}


class _CollectionSearchResults(object):
    
    def __init__(self, collection, _ids):
        self._collection = collection
        self._ids = _ids

    def __iter__(self):
        return (self._collection[_id] for _id in self._ids)

    def __len__(self):
        return len(self._ids)

    count = __len__


class Collection(object):

    def __init__(self, docs):
        self._docs = _index(docs)
        self._engine = None

    def __iter__(self):
        return iter(self._docs.values())

    def __len__(self):
        return len(self._docs)

    def __getitem__(self, _id):
        return self._docs[_id]

    def find(self, filter):
        if self._engine is None:
            self._engine = DocumentSearchEngine(self._docs.values())
        results = self._engine.find(filter)
        return _CollectionSearchResults(self, results)

@@ -1,8 +1,20 @@
+import sys%0A%0A
 from sig
@@ -64,16 +64,50 @@
 hEngine%0A
+from signac.core.json import json%0A
 %0A%0Adef _i
@@ -527,27 +527,107 @@
 _(self, docs
-):%0A
+=None):%0A        if docs is None:%0A            self._docs = dict()%0A        else:%0A    
         self
@@ -862,16 +862,84 @@
 s%5B_id%5D%0A%0A
+    def __setitem__(self, _id, doc):%0A        self._docs%5B_id%5D = doc%0A%0A
     def 
@@ -1104,16 +1104,16 @@
 filter)%0A
-
         
@@ -1159,8 +1159,390 @@
 esults)%0A
+%0A    def dump(self, file=sys.stdout):%0A        for doc in self._docs.values():%0A            file.write(json.dumps(doc) + '%5Cn')%0A%0A    @classmethod%0A    def from_file(cls, fd):%0A        if isinstance(fd, str):%0A            with open(fd) as file:%0A                return cls.from_file(file)%0A        else:%0A            docs = (json.loads(line) for line in fd)%0A            return cls(docs=docs)%0A

Extend Collection implementation.