[Baypiggies] How to create a dict of counts using functional programming

Alex Martelli aleax at google.com
Mon Sep 28 23:12:44 CEST 2015


"functional programming" == "no alteration of existing data"; the `count`
function below is not FP by this definition. (FP "avoids changing-state and
mutable data" is how Wikipedia phrases this definition).

I did mention that by a slightly stricter definition the assignment `item =
next(it, _sentinel)` in my code might also be said to be non-FP (though it
is by the definition above, since local variable `item` is NOT "existing
data" before the assignment) -- but, the stricter definition (forbidding
all assignment) can be respected by using one more function, and argument
passing in lieu of assignment. I.e:

def _count_aux2(item, it, adict);
    return adict if item is _sentinel else _count_aux(it, dict(adict,
*{item: adict.get(item, 0) + 1})

def _count_aux(it, adict):
    return _count_aux2(next(it, _sentinel), it, adict)


Marylin's suggestion *is* FP -- but, it's quadratic (O(N**2)), while this
one is linear (O(N))... like your non-FP one.


Alex


On Mon, Sep 28, 2015 at 1:58 PM, Simeon Franklin <simeonf at gmail.com> wrote:

> I agree wrt to recursion in Python.  But if the correct solution
> (collections.Counter) didn't exist we could write a reduce function.
> Doesn't that seem to be the right FP idiom for the task at hand - it takes
> an input iterable and produces a single calculated result?
>
> >>> def count(total, item):
> ...     total[item] = total.get(item, 0) + 1
> ...     return total
> ...
> >>> data = "Simeon Franklin"
> >>> reduce(count, data, {})
> {'a': 1, ' ': 1, 'e': 1, 'F': 1, 'i': 2, 'k': 1, 'm': 1, 'l': 1, 'o': 1,
> 'n': 3, 'S': 1, 'r': 1}
>
> This doesn't seem so bad to me!
>
>
> On Mon, Sep 28, 2015 at 7:01 AM, Alex Martelli via Baypiggies <
> baypiggies at python.org> wrote:
>
>> If for some weird reason in can't use collections.Counter, as David
>> sensibly suggests, the "FP way" (slow and cranky in Python, which doesn't
>> do tail-call optimization, NOT being a functional programming language) is
>> recursion:
>>
>> _sentinel = object()
>>
>> def _count_aux(it, adict):
>>     item = next(it, _sentinel)
>>     return adict if item is _sentinel else _count_aux(it, dict(adict,
>> *{item: adict.get(item, 0) + 1})
>> def count(iterable):
>>     return _count_aux(iter(iterable), {})
>>
>
>
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://mail.python.org/pipermail/baypiggies/attachments/20150928/0a1f93c9/attachment.html>


More information about the Baypiggies mailing list