Skip to content

Commit 5f157d5

Browse files
qdset
1 parent 0033982 commit 5f157d5

File tree

2 files changed

+140
-81
lines changed

2 files changed

+140
-81
lines changed

orderedsets/__init__.py

Lines changed: 138 additions & 81 deletions
Original file line numberDiff line numberDiff line change
@@ -45,51 +45,107 @@ class _NotProvided:
4545
pass
4646

4747

48-
class OrderedSet(AbstractSet[T]):
48+
from collections import defaultdict
49+
from functools import partialmethod
50+
51+
class OrderedSet(dict, AbstractSet[T]):
4952
"""A set class that preserves insertion order.
5053
5154
It can be used as a drop-in replacement for :class:`set` where ordering is
5255
desired.
5356
"""
54-
55-
def __init__(self, items: Union[Iterable[T], Type[_NotProvided]] = _NotProvided)\
57+
# def __new__(cls, *args: Any, **kwargs: Any)\
58+
# -> None:
59+
# """Create a new :class:`OrderedSet`, optionally initialized with *items*."""
60+
# inst = super().__new__(cls)
61+
# # inst.update(dict.fromkeys(*args, **kwargs))
62+
# # inst = dict.fromkeys(*args, **kwargs)
63+
# return inst
64+
# super().__init__(None)
65+
# if items is _NotProvided:
66+
# self._dict = {}
67+
# else:
68+
# # type-ignore-reason:
69+
# # mypy thinks 'items' can still be Type[_NotProvided] here.
70+
# self._dict = dict.fromkeys(items)
71+
72+
def __init__(self, *args: Any, **kwargs: Any)\
5673
-> None:
5774
"""Create a new :class:`OrderedSet`, optionally initialized with *items*."""
58-
if items is _NotProvided:
59-
self._dict = {}
60-
else:
75+
76+
# if items is _NotProvided:
77+
# self = {}
78+
# else:
6179
# type-ignore-reason:
6280
# mypy thinks 'items' can still be Type[_NotProvided] here.
63-
self._dict = dict.fromkeys(items) # type: ignore[arg-type]
81+
if len(args) > 1:
82+
raise TypeError
83+
if args or kwargs:
84+
super().__init__(dict.fromkeys(*args, **kwargs)) # type: ignore[arg-type]
85+
else:
86+
super().__init__()
87+
# print(self, list(self))
88+
89+
add = dict.setdefault
90+
remove = dict.pop
91+
# __eq__ = frozenset.__ eq__
92+
93+
pop = lambda self: self.popitem()[0]
94+
# union = dict.__ior__
95+
# update = dict.update
96+
# isdisjoint = partialmethod(frozenset.isdisjoint, self.keys())
97+
98+
# list = dict.list
99+
100+
# def add(self, element: T) -> None:
101+
# """Add *element* to this set."""
102+
# self._dict = {**self._dict, **{element: None}}
103+
104+
# __init__ = None
105+
# __init__ = dict.fromkeys
106+
107+
# def __init__(self, items: Union[Iterable[T], Type[_NotProvided]] = _NotProvided)\
108+
# -> None:
109+
# """Create a new :class:`OrderedSet`, optionally initialized with *items*."""
110+
# if items is _NotProvided:
111+
# self._dict = {}
112+
# else:
113+
# # type-ignore-reason:
114+
# # mypy thinks 'items' can still be Type[_NotProvided] here.
115+
# self._dict = dict.fromkeys(items) # type: ignore[arg-type]
64116

65117
def __eq__(self, other: object) -> bool:
66118
"""Return whether this set is equal to *other*."""
67-
return (isinstance(other, Set)
68-
and len(self) == len(other)
69-
and all(i in other for i in self))
119+
return self.keys() == other
70120

71121
def __repr__(self) -> str:
72122
"""Return a string representation of this set."""
73123
if len(self) == 0:
74124
return "OrderedSet()"
75-
return "OrderedSet({" + ", ".join([repr(k) for k in self._dict]) + "})"
125+
return "OrderedSet({" + ", ".join([repr(k) for k in self]) + "})"
76126

77-
def add(self, element: T) -> None:
78-
"""Add *element* to this set."""
79-
self._dict = {**self._dict, **{element: None}}
127+
# def add(self, element: T) -> None:
128+
# """Add *element* to this set."""
129+
# self._dict = {**self._dict, **{element: None}}
80130

81-
def clear(self) -> None:
82-
"""Remove all elements from this set."""
83-
self._dict.clear()
131+
# def clear(self) -> None:
132+
# """Remove all elements from this set."""
133+
# self._dict.clear()
134+
135+
def discard(self, element: T) -> None:
136+
"""Remove *element* from this set if it is present."""
137+
if element in self:
138+
del self[element]
139+
# self.pop(element, None)
84140

85141
def copy(self) -> OrderedSet[T]:
86142
"""Return a shallow copy of this set."""
87-
return OrderedSet(self._dict.copy())
143+
return OrderedSet(self)
88144

89145
def difference(self, *others: Iterable[T]) -> OrderedSet[T]:
90146
"""Return all elements that are in this set but not in *others*."""
91147
if not others:
92-
return OrderedSet(self._dict)
148+
return OrderedSet(self)
93149
other_elems = set.union(*map(set, others))
94150
items = {item: None for item in self if item not in other_elems}
95151
return OrderedSet(items)
@@ -100,18 +156,13 @@ def difference_update(self, *others: Iterable[T]) -> None:
100156
for e in other:
101157
self.discard(e)
102158

103-
def discard(self, element: T) -> None:
104-
"""Remove *element* from this set, if it is present."""
105-
if element in self._dict:
106-
del self._dict[element]
107-
108159
def intersection(self, *others: Iterable[T]) -> OrderedSet[T]:
109160
"""Return the intersection of this set and *others*."""
110161
if not others:
111-
return OrderedSet(self._dict)
162+
return OrderedSet(self)
112163

113164
result_elements = []
114-
for element in self._dict.keys():
165+
for element in self.keys():
115166
if all(element in other for other in others):
116167
result_elements.append(element)
117168

@@ -122,105 +173,111 @@ def intersection_update(self, *others: Iterable[T]) -> None:
122173
if not others:
123174
return
124175

125-
common_keys = list(self._dict.keys())
176+
common_keys = self.keys()
126177
for other in others:
127-
common_keys = [key for key in common_keys if key in set(other)]
178+
common_keys = [key for key in common_keys if key in other]
128179

129-
self._dict = dict.fromkeys(common_keys)
180+
self.clear()
181+
self.update(common_keys)
130182

131183
def isdisjoint(self, s: Iterable[T]) -> bool:
132184
"""Return whether this set is disjoint with *s*."""
133-
return self._dict.keys().isdisjoint(s)
185+
return self.keys().isdisjoint(s)
134186

135187
def issubset(self, s: Iterable[T]) -> bool:
136188
"""Return whether this set is a subset of *s*."""
137-
return all(i in s for i in self)
189+
return set(self).issubset(s)
138190

139191
def issuperset(self, s: Iterable[T]) -> bool:
140192
"""Return whether this set is a superset of *s*."""
141193
return set(self).issuperset(set(s))
142194

143-
def pop(self) -> T:
144-
"""Remove and return the most recently added element from this set."""
145-
items = list(self._dict)
146-
result = items.pop()
147-
self._dict = dict.fromkeys(items)
148-
return result
195+
# def pop(self) -> T:
196+
# """Remove and return the most recently added element from this set."""
197+
# items = list(self._dict)
198+
# result = items.pop()
199+
# self._dict = dict.fromkeys(items)
200+
# return result
149201

150-
def remove(self, element: T) -> None:
151-
"""Remove *element* from this set, raising :exc:`KeyError` if not present."""
152-
del self._dict[element]
202+
# def remove(self, element: T) -> None:
203+
# """Remove *element* from this set, raising :exc:`KeyError` if not present."""
204+
# del self._dict[element]
153205

154206
def symmetric_difference(self, s: Iterable[T]) -> OrderedSet[T]:
155207
"""Return the symmetric difference of this set and *s*."""
156208
return OrderedSet(
157-
dict.fromkeys([e for e in self._dict if e not in s]
158-
+ [e for e in s if e not in self._dict]))
209+
dict.fromkeys([e for e in self if e not in s]
210+
+ [e for e in s if e not in self]))
159211

160212
def symmetric_difference_update(self, s: Iterable[T]) -> None:
161213
"""Update this set to be the symmetric difference of itself and *s*."""
162-
self._dict = self.symmetric_difference(s)._dict
214+
x = self.symmetric_difference(s)
215+
self.clear()
216+
self.update(x)
163217

164218
def union(self, *others: Iterable[T]) -> OrderedSet[T]:
165219
"""Return the union of this set and *others*."""
166-
return OrderedSet(list(self._dict)
220+
return OrderedSet(list(self)
167221
+ [e for other in others for e in other])
168222

169223
def update(self, *others: Iterable[T]) -> None:
170224
"""Update this set to be the union of itself and *others*."""
171-
self._dict = self.union(*others)._dict
225+
x = self | dict.fromkeys(*others)
226+
self.clear()
227+
for e in x:
228+
self.add(e)
172229

173-
def __len__(self) -> int:
174-
"""Return the number of elements in this set."""
175-
return len(self._dict)
230+
# def __len__(self) -> int:
231+
# """Return the number of elements in this set."""
232+
# return len(self._dict)
176233

177-
def __contains__(self, o: object) -> bool:
178-
"""Return whether *o* is in this set."""
179-
return o in self._dict
234+
# def __contains__(self, o: object) -> bool:
235+
# """Return whether *o* is in this set."""
236+
# return o in self._dict
180237

181-
def __iter__(self) -> Iterator[T]:
182-
"""Return an iterator over the elements of this set."""
183-
return iter(self._dict)
238+
# def __iter__(self) -> Iterator[T]:
239+
# """Return an iterator over the elements of this set."""
240+
# return iter(self._dict)
184241

185242
def __and__(self, s: Set[T]) -> OrderedSet[T]:
186243
"""Return the intersection of this set and *s*."""
187244
return self.intersection(s)
188245

189-
def __iand__(self, s: Set[T]) -> OrderedSet[T]:
190-
"""Update this set to be the intersection of itself and *s*."""
191-
result = self.intersection(s)
192-
self._dict = result._dict
193-
return result
246+
# def __iand__(self, s: Set[T]) -> OrderedSet[T]:
247+
# """Update this set to be the intersection of itself and *s*."""
248+
# result = self.intersection(s)
249+
# self._dict = result._dict
250+
# return result
194251

195252
def __or__(self, s: Set[Any]) -> OrderedSet[T]:
196253
"""Return the union of this set and *s*."""
197254
return self.union(s)
198255

199-
def __ior__(self, s: Set[Any]) -> OrderedSet[T]:
200-
"""Update this set to be the union of itself and *s*."""
201-
result = self.union(s)
202-
self._dict = result._dict
203-
return result
256+
# def __ior__(self, s: Set[Any]) -> OrderedSet[T]:
257+
# """Update this set to be the union of itself and *s*."""
258+
# result = self.union(s)
259+
# self._dict = result._dict
260+
# return result
204261

205-
def __sub__(self, s: Set[T]) -> OrderedSet[T]:
206-
"""Return the difference of this set and *s*."""
207-
return self.difference(s)
262+
# def __sub__(self, s: Set[T]) -> OrderedSet[T]:
263+
# """Return the difference of this set and *s*."""
264+
# return self.difference(s)
208265

209-
def __isub__(self, s: Set[T]) -> OrderedSet[T]:
210-
"""Update this set to be the difference of itself and *s*."""
211-
result = self.difference(s)
212-
self._dict = result._dict
213-
return result
266+
# def __isub__(self, s: Set[T]) -> OrderedSet[T]:
267+
# """Update this set to be the difference of itself and *s*."""
268+
# result = self.difference(s)
269+
# self._dict = result._dict
270+
# return result
214271

215-
def __xor__(self, s: Set[Any]) -> OrderedSet[T]:
216-
"""Return the symmetric difference of this set and *s*."""
217-
return self.symmetric_difference(s)
272+
# def __xor__(self, s: Set[Any]) -> OrderedSet[T]:
273+
# """Return the symmetric difference of this set and *s*."""
274+
# return self.symmetric_difference(s)
218275

219-
def __ixor__(self, s: Set[Any]) -> OrderedSet[T]:
220-
"""Update this set to be the symmetric difference of itself and *s*."""
221-
result = self.symmetric_difference(s)
222-
self._dict = result._dict
223-
return result
276+
# def __ixor__(self, s: Set[Any]) -> OrderedSet[T]:
277+
# """Update this set to be the symmetric difference of itself and *s*."""
278+
# result = self.symmetric_difference(s)
279+
# self._dict = result._dict
280+
# return result
224281

225282
def __le__(self, s: Set[T]) -> bool:
226283
"""Return whether this set is a subset of *s*."""
@@ -272,7 +329,7 @@ def __hash__(self) -> int:
272329
if self._my_hash:
273330
return self._my_hash
274331

275-
self._my_hash = hash(frozenset(self))
332+
self._my_hash = hash(frozenset(self._dict))
276333
return self._my_hash
277334

278335
def __eq__(self, other: object) -> bool:

test/test_speed.py

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,8 @@ def test_speed(statement: str, _setup: str, max_slowdown_factor: float,
4747
if platform.python_implementation() == "PyPy":
4848
max_slowdown_factor *= 5
4949

50+
print()
51+
5052
if not skip_mutable:
5153
s_time = timeit(statement, setup=_setup, number=10000)
5254
os_time = timeit(statement,

0 commit comments

Comments
 (0)