summaryrefslogtreecommitdiffstats
path: root/utils_func.py
diff options
context:
space:
mode:
authorJan Pokorný <jpokorny@redhat.com>2014-04-01 14:10:14 +0200
committerJan Pokorný <jpokorny@redhat.com>2014-04-01 14:10:14 +0200
commitd560abca52d05b78c4cf1def0b92652b0e931769 (patch)
tree909109af03abc94bad70bf3810c9508388b8646f /utils_func.py
parentccba7aaeaa7f3f60e987811f9972af77b20c683a (diff)
downloadclufter-d560abca52d05b78c4cf1def0b92652b0e931769.tar.gz
clufter-d560abca52d05b78c4cf1def0b92652b0e931769.tar.xz
clufter-d560abca52d05b78c4cf1def0b92652b0e931769.zip
Refactor: move functional-paradigm helpers utils -> utils_func
Signed-off-by: Jan Pokorný <jpokorny@redhat.com>
Diffstat (limited to 'utils_func.py')
-rw-r--r--utils_func.py86
1 files changed, 86 insertions, 0 deletions
diff --git a/utils_func.py b/utils_func.py
new file mode 100644
index 0000000..eac0305
--- /dev/null
+++ b/utils_func.py
@@ -0,0 +1,86 @@
+# -*- coding: UTF-8 -*-
+# Copyright 2014 Red Hat, Inc.
+# Part of clufter project
+# Licensed under GPLv2 (a copy included | http://gnu.org/licenses/gpl-2.0.txt)
+"""Various functional-paradigm helpers"""
+__author__ = "Jan Pokorný <jpokorny @at@ Red Hat .dot. com>"
+
+from .utils import tuplist
+
+
+apply_preserving_depth = \
+ lambda action: \
+ lambda item: \
+ type(item)(apply_preserving_depth(action)(i) for i in item) \
+ if tuplist(item) else action(item)
+apply_aggregation_preserving_depth = \
+ lambda agg_fn: \
+ lambda item: \
+ agg_fn(type(item)(apply_aggregation_preserving_depth(agg_fn)(i)
+ for i in item)) \
+ if tuplist(item) else item
+apply_aggregation_preserving_passing_depth = \
+ lambda agg_fn, d=0: \
+ lambda item: \
+ agg_fn(type(item)(
+ apply_aggregation_preserving_passing_depth(agg_fn, d+1)(i)
+ for i in item),
+ d+1
+ ) \
+ if tuplist(item) else item
+# name comes from Haskell
+# note: always returns list even for input tuple
+# note: when returning from recursion, should always observe scalar or list(?)
+apply_intercalate = apply_aggregation_preserving_depth(
+ lambda i:
+ reduce(lambda a, b: a + (b if isinstance(b, list) else [b]),
+ i, [])
+)
+
+bifilter = \
+ lambda fnc, seq: \
+ reduce(lambda acc, x: acc[int(not fnc(x))].append(x) or acc,
+ seq, ([], []))
+
+# Given the partitioning function, do the recursive refinement in a way
+# the parts reaching the bottom line in more steps are continually "shaked"
+# towards the end (with stable the relative order, though).
+# Default partitioning function just distinguishes between tuples/lists
+# and other values (presumably scalars) so when passed a tuple/list encoding
+# a graph (tree/forest) in a DFS manner using unrestricted nesting, it will
+# return serialized BFS walk of the same.
+# NOTE if there are scalars already at the start-level depth, use
+# `tail_shake_safe` (not that it provides much more guarantee :-p)
+tailshake = \
+ lambda src, partitioner=(lambda x: not tuplist(x)): \
+ reduce(lambda a, b: a + (tailshake(b, partitioner) if b else b),
+ reduce(lambda a, b: (a[0] + b[0], a[1] + b[1]),
+ tuple(bifilter(partitioner, i) if tuplist(i) else (i, [])
+ for i in src), ([], [])))
+
+tailshake_safe = \
+ lambda src, partitioner=(lambda x: not tuplist(x)): \
+ tailshake(src if all(tuplist(i) for i in src) else (src, ),
+ partitioner)
+
+
+zipped_outlier = type('zipped_outlier', (tuple, ), {})
+zip_empty = type('zip_filler', (str, ), {})("EMPTY")
+loose_zip = lambda a, b: zip(
+ list(a) + (max(len(a), len(b)) - len(a)) * [zip_empty],
+ list(b) + (max(len(a), len(b)) - len(b)) * [zip_empty]
+)
+apply_loose_zip_preserving_depth = \
+ lambda a, b: \
+ (type(a) if type(a) == type(b) else type(a))(
+ [apply_loose_zip_preserving_depth(*p) for p in loose_zip(a, b)]
+ ) if tuplist(a) == tuplist(b) == True else zipped_outlier([a, b])
+# as previous, but with length checking of some sort
+# NOTE: automatically shortens the longer counterpart in the pair
+# to the length of the bigger one
+apply_strict_zip_preserving_depth = \
+ lambda a, b: \
+ (type(a) if type(a) == type(b) else type(a))(
+ [apply_strict_zip_preserving_depth(*p) for p in zip(a, b)]
+ ) if tuplist(a) == tuplist(b) == True and len(a) == len(b) \
+ else zipped_outlier([a, b])