Skip to content

Instantly share code, notes, and snippets.

@mitchellrj
Created July 26, 2011 16:41
Show Gist options
  • Save mitchellrj/1107194 to your computer and use it in GitHub Desktop.
Save mitchellrj/1107194 to your computer and use it in GitHub Desktop.
Constrained list insertion in Python.
def constrained_insert(list_, item, before=None, after=None, strict=True):
""" Given a list and an item to be inserted into that list, attempts
to insert the item into the list in such a way that it is before
any items listed in the 'before' argument and after any of those
listed in the 'after' argument. If this is not possible, raises
a RuntimeError.
If any of the values in before or after do not appear in the
list, ValueError will be raised, unless 'strict' is set to
False.
"""
if before is not None and isinstance(before, basestring):
before = (before, )
elif before is None:
before = ()
if after is not None and isinstance(after, basestring):
after = (after, )
elif after is None:
after = ()
for i in before + after:
if i not in list_:
if strict:
raise ValueError('%s does not appear in the list' % (i,))
else:
if i in before:
before.remove(i)
if i in after:
after.remove(i)
beforepos = min([len(list_)] + [list_.index(s)
for s in before
if s in list_])
afterpos = max([0] + [list_.index(s)
for s in after
if s in list_]) + 1
if before and after and afterpos > beforepos:
raise RuntimeError(('Unabled to resolve a position in %s to satisfy ' \
'the constraints before: %s; after: %s.') % \
(list_, before, after))
if before and not after:
list_.insert(beforepos, item)
else:
# if we don't want it directly before something, insert it as
# early in the list as the 'after' constraint will allow.
list_.insert(afterpos, item)
return list_
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment