[docs]classSequenceSampler(Sequence[T]):""" A class that wraps a :class:`Sequence` of ``T`` objects and provides methods for sampling from it without the need to manipulate or access the underlying data. This is useful for e.g. sub-sampling a ``collection`` where individual indexing operations are expensive, such as a database on disk, or when indexing involves some form of pre-processing. Parameters ---------- collection The collection to wrap. indices The indices of the elements to include in the collection. If ``None``, all elements are included. """def__init__(self,collection:Sequence[T],indices:Sequence[int]|None=None,):self.collection=collectionself.indices=indicesorrange(len(collection))@overloaddef__getitem__(self,index:int)->T:...@overloaddef__getitem__(self,index:slice)->SequenceSampler[T]:...def__getitem__(self,index:int|slice)->T|SequenceSampler[T]:""" Get the element/s at the given ``index``. Parameters ---------- index The index/indices of the element/elements to get. """ifisinstance(index,int):returnself.collection[self.indices[index]]sampled_indices=self.indices[index]returnSequenceSampler(self.collection,sampled_indices)def__len__(self)->int:"""The number of items in the collection."""returnlen(self.indices)def__iter__(self)->Iterator[T]:"""Iterate over the collection."""foriinrange(len(self)):yieldself[i]defshuffled(self,seed:int=42)->SequenceSampler[T]:""" Return a shuffled version of this collection. Parameters ---------- seed The random seed to use for shuffling. """# 1. make a copy of the indicesindices=[*self.indices]# 2. shuffle themnp.random.default_rng(seed).shuffle(indices)# 3. return a new OrderedCollection with the shuffled indicesreturnSequenceSampler(self.collection,indices)defsample_at_most(self,n:int,seed:int=42)->SequenceSampler[T]:""" Return a sampled collection with at most ``n`` elements. """assertn>=0,"n must be non-negative"n=min(n,len(self))returnself.shuffled(seed)[:n]