[309] | 1 | from typing import TypeVar
|
---|
| 2 |
|
---|
| 3 | from tudelft.utilities.immutablelist.AbstractImmutableList import AbstractImmutableList
|
---|
| 4 | from tudelft.utilities.immutablelist.ImmutableList import ImmutableList
|
---|
| 5 |
|
---|
| 6 |
|
---|
| 7 | def bitCount(n:int):
|
---|
| 8 | '''
|
---|
| 9 | @return number of 1's in binary representation of number
|
---|
| 10 | '''
|
---|
| 11 | count = 0
|
---|
| 12 | while (n):
|
---|
| 13 | count += n & 1
|
---|
| 14 | n >>= 1
|
---|
| 15 | return count
|
---|
| 16 |
|
---|
| 17 |
|
---|
| 18 | T=TypeVar("T")
|
---|
| 19 | class SubList(AbstractImmutableList[T]):
|
---|
| 20 | '''
|
---|
| 21 | Selects a specific sublist of the given list.
|
---|
| 22 | This is a sort of subset, but the original order of the elements is
|
---|
| 23 | maintained. Notice this is not a cheap operation.
|
---|
| 24 |
|
---|
| 25 | @param T the element type of all lists that we receive.
|
---|
| 26 | '''
|
---|
| 27 |
|
---|
| 28 | def __init__(self, lis: ImmutableList[T], selection:int):
|
---|
| 29 | '''
|
---|
| 30 | @param lis the list to take the subset of. The list size must be
|
---|
| 31 | ≤ {@link Integer#MAX_VALUE} elements
|
---|
| 32 | @param selection a number. When interpreted binary, eg 1011, the 1's
|
---|
| 33 | indicate selected elements and 0's non-selected
|
---|
| 34 | elements. This number should be in the range
|
---|
| 35 | 0..2^(|list|+1).
|
---|
| 36 | '''
|
---|
| 37 | self._list = lis
|
---|
| 38 | self._selection = selection
|
---|
| 39 |
|
---|
| 40 | def get(self, index:int) -> T:
|
---|
| 41 | return self._list.get(self._getIndex(index))
|
---|
| 42 |
|
---|
| 43 |
|
---|
| 44 | def _getIndex(self, n1:int)->int:
|
---|
| 45 | '''
|
---|
| 46 | @param n the index in our list. We use int as int's are used anyway
|
---|
| 47 | internally in BigInteger for indexing bits.
|
---|
| 48 | @return the index in the original array, which is the index of the nth 1
|
---|
| 49 | in the selection number. NOTICE this is expensive operation as we
|
---|
| 50 | have to iterate to get to the required element.
|
---|
| 51 | '''
|
---|
| 52 | n = n1
|
---|
| 53 | for i in range(self._selection.bit_length()):
|
---|
| 54 | if self._selection >>i & 1:
|
---|
| 55 | if n == 0:
|
---|
| 56 | return i
|
---|
| 57 | n-=1
|
---|
| 58 | raise IndexError("Index out of bounds:" + str(n1))
|
---|
| 59 |
|
---|
| 60 | def size(self) -> int:
|
---|
| 61 | return bitCount(self._selection)
|
---|
| 62 |
|
---|
| 63 | def getSelection(self) -> int:
|
---|
| 64 | return self._selection
|
---|
| 65 |
|
---|
| 66 | def complement(self)-> "SubList[T]" :
|
---|
| 67 | '''
|
---|
| 68 | @return list with all elements from list that were not selected now
|
---|
| 69 | selected, and those that were selected now not selected.
|
---|
| 70 | '''
|
---|
| 71 | # do 111111 XOR the selection.
|
---|
| 72 | sel = (1<<self._list.size()) - 1
|
---|
| 73 | sel = sel ^ self._selection
|
---|
| 74 | return SubList[T](self._list,sel)
|
---|
| 75 |
|
---|
| 76 | def __hash__(self):
|
---|
| 77 | return hash((self._list, self._selection))
|
---|
| 78 |
|
---|
| 79 | def __eq__(self, other):
|
---|
| 80 | return isinstance(other, self.__class__) \
|
---|
| 81 | and self._list==other._list\
|
---|
| 82 | and self._selection==other._selection
|
---|