Home > Mobile >  How to calculate a list based on multiple results from items on a list?
How to calculate a list based on multiple results from items on a list?

Time:03-23

My list is A=[a,b,c,d]. I need to calculate a new list B based on operations between each item in A.

B= [a, b-(a), c-(a (b-a)), d-(a (b-a) (c-(a (b-a)))) ]

Is there a pythonic way of doing this? List A is not always a 4 item list so the solution needs to be generic. Thanks in advance.

CodePudding user response:

All your terms cancel out (c-(a (b-a)) simplifies to c - b, d-(a (b-a) (c-(a (b-a)))) simplifies to d - c), so the real algorithm here is that each term is equal to the matching term minus the prior term. This simplifies things dramatically:

B = [A[0]]  # Initial term has no prior to subtract from it
B  = [x - y for x, y in zip(A[1:], A)]  # All other terms computed by subtracting term n - 1 from term n

If you want to one-line this (ignoring imports) you can stick a virtual 0 in to get the results for the first element without explicitly special-casing it:

from itertools import chain  # At top of file

B = [x - y for x, y in zip(A, chain([0], A))]

If you love using map and friends for microoptimizations, you could replace the latter with:

from operator import sub  # At top of file

B = [*map(sub, A, chain([0], A))]

and push all the work to the C layer (no per-element bytecode execution).

CodePudding user response:

Observe that the expression for your list can be simplified to:

B = [a, b-a, c-b, d-c]

With this in mind, we can use a list comprehension:

[y - x for x, y in zip([0]   data, data)]

For example,

data = [1, 2, 7, 6]
result = [y - x for x, y in zip([0]   data, data)]
print(result)

outputs:

[1, 1, 5, -1]

CodePudding user response:

As suggest by the guys on the comments, this is the simplest and fastest solution:

A = [5, 9, 3, 8]
B = [x - y for x, y in zip(A, [0]   A)]

This outputs:

B
[5, 4, -6, 5]

CodePudding user response:

Assuming you may want to define other operations that can not be simplified as the other answers suggest for your example, you could define each operation as a lambda, with a corresponding list length requirement that is validated before applying it:

from typing import Callable
from dataclasses import dataclass, field
from numbers import Number

@dataclass
class ListOperation:
    list_len_requirement: int
    func_doc: str
    func: Callable = field(repr=False)

def apply_list_operations(xs: list[Number],
                          list_ops: list[ListOperation]) -> list[Number]:
    new_xs = []
    for op in list_ops:
        # TODO: Maybe move this check to be part of ListOperation.
        if op.list_len_requirement > len(xs):
            raise ValueError('List not large enough')
        new_xs.append(op.func(xs))
    return new_xs

def main() -> None:
    list_operations = [
        ListOperation(list_len_requirement=1,
                      func_doc='a',
                      func=lambda xs: xs[0]),
        ListOperation(list_len_requirement=2,
                      func_doc='b-(a)',
                      func=lambda xs: xs[1] - (xs[0])),
        ListOperation(list_len_requirement=3,
                      func_doc='c-(a (b-a))',
                      func=lambda xs: xs[2] - (xs[0]   (xs[1] - xs[0]))),
        ListOperation(list_len_requirement=4,
                      func_doc='d-(a (b-a) (c-(a (b-a))))',
                      func=lambda xs: xs[3] - (xs[0]   (xs[1] - xs[0])   (xs[2] - (xs[0]   (xs[1] - xs[0]))))),
    ]
    print('\n'.join(str(op) for op in list_operations))
    a, b, c, d = 1, 2, 3, 4
    A = [a, b, c, d]
    print(f'{A = }')
    B = apply_list_operations(A, list_operations)
    print(f'{B = }')

if __name__ == '__main__':
    main()

Output:

ListOperation(list_len_requirement=1, func_doc='a')
ListOperation(list_len_requirement=2, func_doc='b-(a)')
ListOperation(list_len_requirement=3, func_doc='c-(a (b-a))')
ListOperation(list_len_requirement=4, func_doc='d-(a (b-a) (c-(a (b-a))))')
A = [1, 2, 3, 4]
B = [1, 1, 1, 1]

CodePudding user response:

Pythonic way:-

A = [1,2,3,4]
B = [A[0]] [A[i 1]-A[i] for i in range(len(A)-1)]
  • Related