Reputation: 53
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
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
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