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
|
---|