0

I am new to Python. I want to apply various permutations of three functions f, g, and h where juxtaposition means function composition (e.g., fg(x) = f(g(x))) to say, a list x of boolean integers, and put the results in an array. To make it easy to verify that each array element gets assigned the correct value, I want its index to reflect the permutation that generated it.

What I came up with below works fine but is there a better way? Specifically, I'd prefer that something shorter than "(list(c[p.index(" appear between the current function and the previously applied ones, if possible.

def f(x):
#   manipulate x
    return x
def g(x):
#   manipulate x
    return x
def h(x):
#   manipulate x
    return x

def apply_perms(x):
    assert (len(x) == 10)

    p = (
    'f','g','h',
    'fg','gh','hf',
    'ffg','fgh','fhf'
    )

    c = [[0] * 10 for _ in range(9)]

    c[p.index('f')] = f(list(x))
    c[p.index('g')] = g(list(x))
    c[p.index('h')] = h(list(x))
    c[p.index('fg')] = f(list(c[p.index('g')]))
    c[p.index('gh')] = g(list(c[p.index('h')]))
    c[p.index('hf')] = h(list(c[p.index('f')]))
    c[p.index('ffg')] = f(list(c[p.index('fg')]))
    c[p.index('fgh')] = f(list(c[p.index('gh')]))
    c[p.index('fhf')] = f(list(c[p.index('hf')]))

    return c

x = [1,0,1,0,0,0,1,0,0,1]
apply_perms(x)
mathematrucker
  • 166
  • 1
  • 9
  • Your question is unclear. Are `f`, `g` and `h` supposed to take a list as argument and return a list or are they supposed to operate on individual elements of the list? As written right now your code will generate an error because the functions return `None`, to which you can't apply `list(...)`: `TypeError: 'NoneType' object is not iterable` – walnut Oct 20 '19 at 00:29
  • 1
    Can't you use a simple dictionary? If you assign a dictionary to `c` then you could just do `c['f'] = f(list(x))`, and it would be a lot more readable. – Michele Bastione Oct 20 '19 at 00:42
  • @MicheleBastione yes, now that you mention it, I think that's all I need. I'm not used to dictionaries yet so went with the known---arrays---instead. Will change c to a dictionary and see how it goes. Thank you. – mathematrucker Oct 20 '19 at 00:51
  • @uneven_mark I edited the question somewhat to hopefully resolve your question. – mathematrucker Oct 20 '19 at 00:52
  • 1
    @mathematrucker My point is that if the functions already return lists, all the calls to `list(...)` are completely redundant. But your functions should probably return copies instead of modifying the argument. – walnut Oct 20 '19 at 00:55
  • @uneven_mark my definition of c wasn't working initially because I hadn't yet learned how Python variables differ from C variables. I found list() in some tutorial somewhere and saw that it would probably fix things, which it did, but aha, the root of the problem was that the functions were returning the argument. Thanks much...will fix that too. – mathematrucker Oct 20 '19 at 01:11
  • @mathematrucker If you want to compare it to C, in Python all names are basically pointers. If you modify the function argument as in `x[0] = 1`, you are modifying the caller's list as well, however direct assignment is assignment of pointers, not values, e.g. `x = 1` does not affect the caller. `list(x)` makes a copy if `x` is already a list. But that should probably happen already in the functions themselves, rather than in the caller. – walnut Oct 20 '19 at 01:19
  • @uneven_mark yes it's better for the copies to be created in the functions, for, among other reasons, doing so will further shorten the text I was trying to shorten in my question. After learning more about Python variables, I was thinking they seemed a lot like pointers---it's good to have the hunch confirmed. – mathematrucker Oct 20 '19 at 01:33
  • Because it is hard to self-reference dictionary entries (see https://stackoverflow.com/a/3740531/2327394) I stuck with defining c as an array; manipulating and returning copies of the function arguments did at least remove "list()" from the definition. – mathematrucker Oct 21 '19 at 19:19

0 Answers0