Nihar
Nihar

Reputation: 53

How to iterate over an multidimensional arbitrary list in python

I have an expression Tree, that generates the Tree list. The list variers depending on the expression that are used to calculate the number for example,

T = ['-', ['+', ['-', 75, ['-', 10, 3]], ['-', 100, 50]], 3]

Or

T = ['+', ['*', 5, 4] ,['-', 100, ['/', 20, 2] ]]

I want to iterate over each and every element of the Tree and store the index of the operators, list of all the operators, index of the numbers and the list of numbers in an array. For this, I am trying to figure out a way that I can loop into the list and then just check if the type is a string which would mean it is an operator and store that index and value in the respective array by appending, else if the type is number then store it in the array with all the numbers.

I tried the below code

T = T =  ['-', ['+', ['-', 75, ['-', 10, 3]], ['-', 100, 50]], 3]
for i in range(0,len(T)):
    if type(T[i]) != int:
        for j in range(0,len(T[i])):
            print(T[i][j])
    else:
        print(T[i])

Running the code gives the output:

-
+
['-', 75, ['-', 10, 3]]
['-', 100, 50]
3

What we are basically trying to achieve is to go inside the list till we could depending on the list size. Any ideas on how this could be possible?

My answer would basically be:

address list of the operators is  [[0], [1, 0], [1, 1, 0], [1, 1, 2, 0], [1, 2, 0]] 
    
list of the operators is ['-', '+', '-', '-', '-'] 
    
address of the numbers is [[1, 1, 1], [1, 1, 2, 1], [1, 1, 2, 2], [1, 2, 1], [1, 2, 2], [2]] 
    
list of the numbers is [75, 10, 3, 100, 50, 3] 

Upvotes: 3

Views: 233

Answers (2)

Ajax1234
Ajax1234

Reputation: 71471

You can use a single recursive generator function with collections.defaultdict:

from collections import defaultdict
def get_ops(t, p = []):
   if isinstance(t, int):
      yield ('val', t, p)
   else:
      yield ('op', t[0], p+[0])
      yield from get_ops(t[1], p+[1])
      yield from get_ops(t[2], p+[2])

T, d = ['-', ['+', ['-', 75, ['-', 10, 3]], ['-', 100, 50]], 3], defaultdict(list)
for a, b, c in get_ops(T):
    d[f'{a}_index'].append(c)
    d[f'{a}s'].append(b)

print(dict(d))

Output:

{
  'op_index': [[0], [1, 0], [1, 1, 0], [1, 1, 2, 0], [1, 2, 0]], 
  'ops': ['-', '+', '-', '-', '-'], 
  'val_index': [[1, 1, 1], [1, 1, 2, 1], [1, 1, 2, 2], [1, 2, 1], [1, 2, 2], [2]], 
  'vals': [75, 10, 3, 100, 50, 3]
}

Upvotes: 1

j1-lee
j1-lee

Reputation: 13939

You can use recursive functions. The following can be improved, for example by processing operators and numbers simultaneously.

T = ['-', ['+', ['-', 75, ['-', 10, 3]], ['-', 100, 50]], 3]

def evaluate(arg): # not requested, but why not?
    if type(arg) is list:
        return eval(f'{evaluate(arg[1])} {arg[0]} {evaluate(arg[2])}')
    else:
        return arg

def get_ops(arg): # returns (list of operators, list of their indices)
    ops = [arg[0]] # first elem is an operator, so add it
    idx = [[0]] # add this index 0
    for i in (1, 2): # for each position 1 and 2,
        if type(arg[i]) is list: # if NOT scalar
            ops_sub, idx_sub = get_ops(arg[i]) # recurse!
            ops += ops_sub # add the list of ops from the sublist
            idx += [[i] + x for x in idx_sub] # add idx list from the sublist,
                                              # while the position of the sublist
                                              # being PREPENDED to each idx
    return ops, idx

def get_nums(arg): # basically the same goes here
    nums = []
    idx = []
    for i in (1, 2):
        if type(arg[i]) is list:
            nums_sub, idx_sub = get_nums(arg[i])
            nums += nums_sub
            idx += [[i] + x for x in idx_sub]
        else: # if scalar, this IS a number, so add it to the output
            nums.append(arg[i])
            idx.append([i])
    return nums, idx

print(get_ops(T))
print(get_nums(T))
print(evaluate(T))

The result:

(['-', '+', '-', '-', '-'], [[0], [1, 0], [1, 1, 0], [1, 1, 2, 0], [1, 2, 0]])
([75, 10, 3, 100, 50, 3], [[1, 1, 1], [1, 1, 2, 1], [1, 1, 2, 2], [1, 2, 1], [1, 2, 2], [2]])
115

Upvotes: 1

Related Questions