Home > Blockchain >  Print Value from Key and Value in one list in a new empty list based on matching elements
Print Value from Key and Value in one list in a new empty list based on matching elements

Time:02-10

Logic Behind Problem: When building a route you need two steps in order to perform a direction. For example if you go from Step1 to Step2 that is right. But Step1 to Step3 is left. The steps need to be in pairs in order to determine direction.

Issue: I have a function that produces a 'Direction' based on a pair of elements in 'StepName'. If a routes 'StepName' pair is already defined with 'Direction' it should be able to produce the same 'Direction' in another route dictionary if it contains the same pair of elements in a sequence of pairs. Doesn't matter at what index the pair is located in the list

For example:

  • 104-1 to 104-2 produces 'Left' in 'Direction'
  • 104-2 to 105-A produces 'Right' in 'Direction'
  • 105-A to 105-D produces 'Right' in 'Direction'

Code:

route1 = {
    'RouteID': 1,
    'StepID': [1, 2, 3, 4],
    'StepName': ['104-1', '104-2', '105-A', '105-D'],
    'Direction': ['Left', 'Right', 'Right']}

route2 = {
    'RouteID': 2,
    'StepID': [1, 2, 3, 4],
    'StepName': ['104-2', '105-A', '105-C', '105-B'],
    'Direction': []}

def routeMapper(longRoute, subRoute):
    for i, v in enumerate(subRoute['StepName']):
        found = False
        for j, b in enumerate(longRoute['StepName']):
            if v == b:
                found = True
                subRoute['Direction'].append(longRoute['Direction'][j])
        if not found:
            subRoute['Direction'].append(False)

routeMapper(route1, route2)
print(route2)

Output:

{'RouteID': 2, 'StepID': [1, 2, 3, 4], 'StepName': ['104-2', '105-A', '105-C', '105-B'], 'Direction': ['Right', 'Right', False, False]}

As you can see it is comparing what each index element direction it is assigned to. I want it to be seen in pairs instead of single.

Desired Output: (for 'Direction')

{'RouteID': 2, 'StepID': [1, 2, 3, 4], 'StepName': ['104-2', '105-A', '105-C', '105-B'], 'Direction': ['Right', False, False, False]}

The reason this output makes sense is because in route1 104-2 to 105-A produces 'Right' even though it is 1 and 2 in the index as a pair compared to it being at the 0 and 1 index in route2. As long as the pair is found in the list it should be able to produce the direction.

CodePudding user response:

I first created a list named pair1 that will keep hold of i & i 1 elements from the subRoute's StepName in the first loop. I've also done the same to the longRoute in the second loop. Then if the first element of each pair and both of the pairs match, the function will append the direction of that pair's. If not, it will append False. (I had to restructure the loops to make this work)

def routeMapper(longRoute, subRoute):
    for i in range(len(subRoute['StepName']) - 1):
        found = False
        pair1 = [subRoute['StepName'][i], subRoute['StepName'][i 1]]
        for j in range(len(longRoute['StepName']) - 1):
            pair2 = [longRoute['StepName'][j], longRoute['StepName'][j 1]]
            if pair1[0]==pair2[0] and pair1 == pair2:
                found = True
                subRoute['Direction'].append(longRoute['Direction'][j])
        if not found:
                subRoute['Direction'].append(False)

    #Output: {'RouteID': 2, 'StepID': [1, 2, 3, 4], 'StepName': ['104-2', '105-A', '105-C', '105-B'], 'Direction': ['Right', False, False]}

CodePudding user response:

I think the best solution would be to:

  • create a dictionary mapping location pairs (104-1 to 104-2) to their respective directions (Left): function route_directions
  • then, using this dictionnary we could compute the second route directions quite easily: function derive_directions
def route_directions(route):
    directions = route['Direction']
    steps = route_steps(route)
    return {step:direction for step, direction in zip(steps, directions)}

# Utility function (we could also use itertools.pairwise instead of this)
def route_steps(route):
    return zip(route['StepName'], route['StepName'][1:])

def derive_directions(route, existing_directions):
    return [existing_directions.get(step, False) for step in route_steps(route)]

Using all these functions, we can simply derive route2 directions from route1:

route_directions = route_dict(route1)
route2['Direction'] = derive_directions(route2, route_directions)

Few things used here

  • zip() that I also tried to describe a bit here. Basically it match two (or more) list element-wise, for example, zip([1, 2, 3], [10, 20, 30]), will produce the following tuples (1, 10), (2, 20), (3, 30).
  • This code also uses the fact that tuples can be used as dictionary keys, here is what the route_directions looks like:
{('104-1', '104-2'): 'Left',
 ('104-2', '105-A'): 'Right',
 ('105-A', '105-D'): 'Right'}
  • Related