Python Forum
Moving to Functional
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Moving to Functional
#1
Can anyone help explain how to make this snippet follow a more functional style? I was able to functionalize other portions of the code but having trouble with this.
def Report ():
    data = Load ()
    Report = ""
    LastDate = GetDate (data[0])
    Count = 0; Counts = [0,0,0,0,0,0,0,0,0,0]
    for rec in data:
        Count += 1
        ThisDate = RecToDate (rec)
        if ThisDate != LastDate:
            Report += Summary (Count,Counts)
            Count = 0; Counts = [0,0,0,0,0,0,0,0,0,0]
            LastDate = ThisDate
        for j in range (10): Counts[j] += RecRan (rec,j)
        Report += str (rec)
    return Report
Reply
#2
I would try the following
from itertools import groupby
def report():
    data = Load()
    report = []
    for date, irec in groupby(data, key=lambda r: RecToDate(r)):
        irec = list(irec)
        counts = [0] * 10
        for rec in irec:
            for j in range(10):
                counts[j] += RecRan(rec, j)
            report.append(str(rec))
        report.append(Summary(len(irec), counts))
    return ''.join(report)
Reply
#3
Thank you very much. I will study your suggestion. I wonder if there is a way to further reduce mutation and state.
Reply
#4
I tested your code and it worked with minor mods - nice work!
Reply
#5
Please post the modified code and we'll see if further reduction is possible.
Reply
#6
I wonder how to minimize loops and variables. Overall the code is still imperative.

def CountRuns (rec,counts):
    for j in range(10): counts[j] += RecRan(rec, j)

def Report ():
    data = Load ()
    report = [] 
    for date, irec in groupby(data, key=RecToDate):
        irec = list(irec) 
        counts = [0] * 10
        for rec in irec:
            CountRuns (rec,counts)
            report.append(StrRec(rec))
        report.append(Summary(len(irec), counts, Strdate(date)))
    return ''.join(report)
Reply
#7
Here is my attempt in a non imperative style
import itertools as itt
import numpy as np
    
def count_incr(rec):
    return np.array(RecRan(rec, j) for j in range(10))
 
def ireport_group(date, irec):
    return itt.chain(
        (StrRec(rec) for rec in irec),
        (Summary(len(irec),
            list(np.sum(count_incr(rec) for rec in irec)), Strdate(date)),))

def Report():
    return ''.join(
        itt.chain.from_iterable(
            ireport_group(date, list(irec))
                for date, irec in itt.groupby(Load(), key=RecToDate)))
Reply
#8
Thank you very much again - I'm impressed.

Unfortunately that takes me down what appears to be a huge rabbit hole with:

RuntimeError: The current Numpy installation ('C:\\Users\\Autologin\\AppData\\Local\\Programs\\Python\\Python39\\lib\\site-packages\\numpy\\__init__.py') fails to pass a sanity check due to a bug in the windows runtime. See: https://tinyurl.com/y3dm3h86

I'm not asking you to solve this also but maybe someone knows an easy fix off hand. My numpy install is new.
Reply
#9
A quick fix is to not use numpy
from functools import reduce
import itertools as itt

ZERO = [0] * 10

def add_list(a, b):
    return [x + y for x, y in zip(a, b)]

    
def count_incr(rec):
    return [RecRan(rec, j) for j in range(10)]
 
def ireport_group(date, irec):
    return itt.chain(
        (StrRec(rec) for rec in irec),
        (Summary(
            len(irec),
            reduce(add_list, (count_incr(rec) for rec in irec), ZERO),
            Strdate(date)),))

def Report():
    return ''.join(
        itt.chain.from_iterable(
            ireport_group(date, list(irec))
                for date, irec in itt.groupby(Load(), key=RecToDate)))
Another solution is probably to install numpy 1.19.3 as suggested in the dev page that you linked.
Reply
#10
NumPy really shouldn't be necessary to program in a functional style anyway.

I haven't really looked at the code much, so can't really provide many comments. You might like to look at the Toolz library that provides a lot of the kinds of functions you'd get in more mainstream functional languages.
Reply


Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020