Last active
December 15, 2015 11:28
-
-
Save dxlbnl/5252734 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
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