Skip to content

Instantly share code, notes, and snippets.

@dxlbnl
Last active December 15, 2015 11:28
Show Gist options
  • Save dxlbnl/5252734 to your computer and use it in GitHub Desktop.
Save dxlbnl/5252734 to your computer and use it in GitHub Desktop.
from functools import partial
from itertools import chain, ifilter, islice, izip_longest
import time
# First approach
def first_approach_split(lines, width, space):
"""
The proper way ?
"""
new_lines = []
for line in lines:
_space = ''
lns = []
if len(line) > width:
while len(line) > (width - len(_space)):
lns.append(_space + line[:(width - len(_space))])
line = line[(width - len(_space)):]
_space = space
lns.append(_space + line)
new_lines += lns
else:
new_lines.append(line)
return new_lines
# Fast, but with sideeffects
def splice_split_sideeffects(lines, width, space):
"""
The improper way ?
"""
for i, line in enumerate(lines):
if len(line) > width:
lines[i:i+1] = [
line[0:width],
space + line[width:]
]
return lines
# VK, comprehension split
def wrap_line(line, width, space):
short_width = width - len(space)
yield line[:width]
for i in xrange(width, len(line), short_width):
yield space + line[i: i + short_width]
def vk_comprehension_split(lines, width, space):
return [l for line in lines for l in wrap_line(line, width, space)]
# VK, yield split
def vk_yield_split(lines, width, space):
short_width = width - len(space)
for line in lines:
yield line[:width]
for i in xrange(width, len(line), short_width):
yield space + line[i: i + short_width]
# same, but with list appending.
def list_append_split(lines, width, space):
l = []
short_width = width - len(space)
for line in lines:
l.append(line[:width])
for i in xrange(width, len(line), short_width):
l.append(space + line[i: i + short_width])
return l
# TM, functional approach
def compose(*funcs):
"""Return a function such that compose(a,b,c)(arg1, arg2, arg3)
is equivalent to a(b(c(arg1, arg2, arg3)))."""
# See http://bugs.python.org/issue1660179
def _composefunc(*args, **kw):
l = reversed(funcs)
rv = l.next()(*args, **kw)
for f in l:
rv = f(rv)
return rv
return _composefunc
def concat(xs):
return (y for x in xs for y in x)
concat_map = compose(concat, map)
def take(n, iterable):
return islice(iterable, n)
def drop(n, iterable):
return islice(iterable, n, None)
def splitat(n, xs):
return (take(n, xs), drop(n, xs))
def prepend(xs):
return partial(chain, xs)
def chunk(chunk_size, xs):
def _grouper(n, xs, fillvalue=None):
return izip_longest(*[iter(xs)]*n, fillvalue=fillvalue)
fillvalue = object()
xss = _grouper(chunk_size, xs, fillvalue)
return (ifilter(lambda x: x is not fillvalue, xs) for xs in xss)
## Solution.
def tm_wrap_line(width, prefix, line):
head, tail = splitat(width, line)
return [head] + map(prepend(prefix), chunk(width - len(prefix), tail))
def wrap_lines(width, prefix, lines):
return concat_map(partial(tm_wrap_line, width, prefix), lines)
## Hack.
normalize = ''.join
# simple timeit utility.
class TimeIt(object):
def __init__(self, name):
self.name = name
def __enter__(self):
self.start = time.time()
def __exit__(self, type, value, traceback):
if type:
print "ERROR", type, value, traceback
print "Executed in: {:.4f}s | {}".format(time.time() - self.start, self.name)
resp_lines = [
str(range(i)) for i in range(20, 1000,6)
]
width = 80
space = " "
iterations = 1000
ref = '\n'.join(vk_comprehension_split(resp_lines, width, space))
with TimeIt('vk_comprehension_split'):
for i in range(iterations):
s = '\n'.join(vk_comprehension_split(resp_lines, width, space))
assert s == ref, 'wrong answer'
with TimeIt('vk_yield_split'):
for i in range(iterations):
s = '\n'.join(vk_yield_split(resp_lines, width, space))
assert s == ref, 'wrong answer'
with TimeIt('first_approach_split'):
for i in range(iterations):
s = '\n'.join(first_approach_split(resp_lines, width, space))
assert s == ref, 'wrong answer'
with TimeIt('list_append_split'):
for i in range(iterations):
s = '\n'.join(list_append_split(resp_lines, width, space))
assert s == ref, 'wrong answer'
with TimeIt('splice_split_sideeffects'):
for i in range(iterations):
s = '\n'.join(splice_split_sideeffects(resp_lines[::], width, space))
assert s == ref, 'wrong answer'
with TimeIt('tm_functional'):
for i in range(iterations):
s = '\n'.join(map(normalize, wrap_lines(width, space, resp_lines)))
assert s == ref, 'wrong answer'
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment