class SortedListWithKey(MutableSequence):
  def __init__(self, iterable=None, key=lambda val: val, value_orderable=True, load=1000):
    self._key = key
    self._list = SortedList(load=load)
    self._ordered = value_orderable
    if value_orderable:
      self._pair = lambda key, value: (key, value)
    else:
      self._pair = Pair
    if iterable is not None:
      self.update(iterable)
  def clear(self):
    self._list.clear()
  def add(self, value):
    pair = self._pair(self._key(value), value)
    self._list.add(pair)
  def update(self, iterable):
    _key, _pair = self._key, self._pair
    self._list.update(_pair(_key(val), val) for val in iterable)
  def __contains__(self, value):
    _list = self._list
    _key =  self._key(value)
    _pair = self._pair(_key, value)
    if self._ordered:
      return _pair in _list
    _maxes = _list._maxes
    if _maxes is None:
      return False
    pos = bisect_left(_maxes, _pair)
    if pos == len(_maxes):
      return False
    _lists = _list._lists
    idx = bisect_left(_lists[pos], _pair)
    len_lists = len(_lists)
    len_sublist = len(_lists[pos])
    while True:
      pair = _lists[pos][idx]
      if _key != pair.key:
        return False
      if value == pair.value:
        return True
      idx += 1
      if idx == len_sublist:
        pos += 1
        if pos == len_lists:
          return False
        len_sublist = len(_lists[pos])
        idx = 0
  def discard(self, value):
    _list = self._list
    _key =  self._key(value)
    _pair = self._pair(_key, value)
    if self._ordered:
      _list.discard(_pair)
      return
    _maxes = _list._maxes
    if _maxes is None:
      return
    pos = bisect_left(_maxes, _pair)
    if pos == len(_maxes):
      return
    _lists = _list._lists
    idx = bisect_left(_lists[pos], _pair)
    len_lists = len(_lists)
    len_sublist = len(_lists[pos])
    while True:
      pair = _lists[pos][idx]
      if _key != pair.key:
        return
      if value == pair.value:
        _list._delete(pos, idx)
        return
      idx += 1
      if idx == len_sublist:
        pos += 1
        if pos == len_lists:
          return
        len_sublist = len(_lists[pos])
        idx = 0
  def remove(self, value):
    _list = self._list
    _key =  self._key(value)
    _pair = self._pair(_key, value)
    if self._ordered:
      _list.remove(_pair)
      return
    _maxes = _list._maxes
    if _maxes is None:
      raise ValueError
    pos = bisect_left(_maxes, _pair)
    if pos == len(_maxes):
      raise ValueError
    _lists = _list._lists
    idx = bisect_left(_lists[pos], _pair)
    len_lists = len(_lists)
    len_sublist = len(_lists[pos])
    while True:
      pair = _lists[pos][idx]
      if _key != pair.key:
        raise ValueError
      if value == pair.value:
        _list._delete(pos, idx)
        return
      idx += 1
      if idx == len_sublist:
        pos += 1
        if pos == len_lists:
          raise ValueError
        len_sublist = len(_lists[pos])
        idx = 0
  def __delitem__(self, index):
    del self._list[index]
  def __getitem__(self, index):
    if isinstance(index, slice):
      return list(tup[1] for tup in self._list[index])
    else:
      return self._list[index][1]
  def __setitem__(self, index, value):
    _key, _pair = self._key, self._pair
    if isinstance(index, slice):
      self._list[index] = list(_pair(_key(val), val) for val in value)
    else:
      self._list[index] = _pair(_key(value), value)
  def __iter__(self):
    return iter(tup[1] for tup in iter(self._list))
  def __reversed__(self):
    return iter(tup[1] for tup in reversed(self._list))
  def __len__(self):
    return len(self._list)
  def bisect_left(self, value):
    pair = self._pair(self._key(value), value)
    return self._list.bisect_left(pair)
  def bisect(self, value):
    pair = self._pair(self._key(value), value)
    return self._list.bisect(pair)
  def bisect_right(self, value):
    pair = self._pair(self._key(value), value)
    return self._list.bisect_right(pair)
  def count(self, value):
    _list = self._list
    _key =  self._key(value)
    _pair = self._pair(_key, value)
    if self._ordered:
      return _list.count(_pair)
    _maxes = _list._maxes
    if _maxes is None:
      return 0
    pos = bisect_left(_maxes, _pair)
    if pos == len(_maxes):
      return 0
    _lists = _list._lists
    idx = bisect_left(_lists[pos], _pair)
    total = 0
    len_lists = len(_lists)
    len_sublist = len(_lists[pos])
    while True:
      pair = _lists[pos][idx]
      if _key != pair.key:
        return total
      if value == pair.value:
        total += 1
      idx += 1
      if idx == len_sublist:
        pos += 1
        if pos == len_lists:
          return total
        len_sublist = len(_lists[pos])
        idx = 0
  def copy(self):
    _key, _ordered, _load = self._key, self._ordered, self._list._load
    kwargs = dict(key=_key, value_orderable=_ordered, load=_load)
    return SortedListWithKey(self, **kwargs)
  def __copy__(self):
    return self.copy()
  def append(self, value):
    pair = self._pair(self._key(value), value)
    self._list.append(pair)
  def extend(self, iterable):
    _key, _pair = self._key, self._pair
    self._list.extend(_pair(_key(val), val) for val in iterable)
  def insert(self, index, value):
    pair = self._pair(self._key(value), value)
    self._list.insert(index, pair)
  def pop(self, index=-1):
    return self._list.pop(index)[1]
  def index(self, value, start=None, stop=None):
    _list = self._list
    _key =  self._key(value)
    _pair = self._pair(_key, value)
    if self._ordered:
      return _list.index(_pair, start, stop)
    _len = _list._len
    if start == None:
      start = 0
    if start < 0:
      start += _len
    if start < 0:
      start = 0
    if stop == None:
      stop = _len
    if stop < 0:
      stop += _len
    if stop > _len:
      stop = _len
    if stop <= start:
      raise ValueError
    _maxes = _list._maxes
    pos = bisect_left(_maxes, _pair)
    if pos == len(_maxes):
      raise ValueError
    _lists = _list._lists
    idx = bisect_left(_lists[pos], _pair)
    len_lists = len(_lists)
    len_sublist = len(_lists[pos])
    while True:
      pair = _lists[pos][idx]
      if _key != pair.key:
        raise ValueError
      if value == pair.value:
        loc = _list._loc(pos, idx)
        if start <= loc < stop:
          return loc
      idx += 1
      if idx == len_sublist:
        pos += 1
        if pos == len_lists:
          raise ValueError
        len_sublist = len(_lists[pos])
        idx = 0
  def as_list(self):
    return list(tup[1] for tup in self._list.as_list())
  def __add__(self, that):
    result = SortedListWithKey(
      key=self._key,
      value_orderable=self._ordered,
      load=self._list._load)
    values = self.as_list()
    values.extend(that)
    result.update(values)
    return result
  def __iadd__(self, that):
    self.update(that)
    return self
  def __mul__(self, that):
    values = self.as_list() * that
    return SortedListWithKey(
      values, key=self._key, value_orderable=self._ordered,
      load=self._list._load)
  def __imul__(self, that):
    values = self.as_list() * that
    self.clear()
    self.update(values)
    return self
  def __eq__(self, that):
    return ((len(self) == len(that))
        and all(lhs == rhs for lhs, rhs in zip(self, that)))
  def __ne__(self, that):
    return ((len(self) != len(that))
        or any(lhs != rhs for lhs, rhs in zip(self, that)))
  def __lt__(self, that):
    return ((len(self) <= len(that))
        and all(lhs < rhs for lhs, rhs in zip(self, that)))
  def __le__(self, that):
    return ((len(self) <= len(that))
        and all(lhs <= rhs for lhs, rhs in zip(self, that)))
  def __gt__(self, that):
    return ((len(self) >= len(that))
        and all(lhs > rhs for lhs, rhs in zip(self, that)))
  def __ge__(self, that):
    return ((len(self) >= len(that))
        and all(lhs >= rhs for lhs, rhs in zip(self, that)))
  @recursive_repr
  def __repr__(self):
    return '%s(%s, key=%r, value_orderable=%r, load=%r)' % (
        self.__class__.__name__, self.as_list(), self._key,
        self._ordered, self._list._load)
Beispiel #2
0
class SortedListTestCase(unittest.TestCase):
  def setUp(self):
    self.sorted_list = SortedList()

  @property
  def is_sorted(self):
    for i, item in enumerate(self.sorted_list):
      if i == 0:
        current = item
      else:
        if current > item:
          return False
    return True

  def test_append_is_sorted(self):
    items = []
    for _ in xrange(200):
      num = random.uniform(-100, 100)
      self.sorted_list.append(num)
      self.assertTrue(self.is_sorted)

  def test_append_keeps_items(self):
    items = []
    for _ in xrange(200):
      num = random.uniform(-100, 100)
      self.sorted_list.append(num)
      items.append(num)
      items.sort()
      for i, j in zip(items, self.sorted_list):
        self.assertEqual(i, j)

  def test_extend_is_sorted(self):
    nums = range(-100, 100)
    random.shuffle(nums)
    self.sorted_list.extend(nums)
    self.assertTrue(self.is_sorted)

  def test_extend_keeps_items(self):
    nums = range(-100, 100)
    random.shuffle(nums)
    self.sorted_list.extend(nums)
    nums.sort()
    for i, j in zip(nums, self.sorted_list):
      self.assertEqual(i, j)

  def test_setitem_is_sorted(self):
    nums = xrange(-100, 100)
    self.sorted_list.extend(nums)

    for _ in xrange(200):
      self.sorted_list[random.randint(0, len(self.sorted_list) - 1)] = random.uniform(-100, 100)
      self.assertTrue(self.is_sorted)

  def test_setitem_keeps_items(self):
    nums = range(-100, 100)
    self.sorted_list.extend(nums)

    for _ in xrange(200):
      index = random.randint(0, len(self.sorted_list) - 1)
      num = random.uniform(-100, 100)
      self.sorted_list[index] = num
      nums[index] = num
      nums.sort()
      for i, j in zip(self.sorted_list, nums):
        self.assertEqual(i, j)