user25976
user25976

Reputation: 1025

Sorting and re-numbering values in Python dictionary

I have the following Python dictionaries:

road_dict = {0:[1L,2L], 1:[3L], 2:[4L,5L]}
dist_dict = {1L: 4.1, 2L: 2.1, 3L: 4, 4L: 2.1, 5L: 6}
num_dict = {0:[2,4], 1:[5], 2:[1,3]

The first one, road_dict, has road IDs as keys and home IDs associated as values. The second, dist_dict, has the same home IDs as keys and their distance along the road as values. The third, num_dict, has the same road IDs as keys and number associated with the same homes as values.

I am trying to re-number these homes based on their distance along the road. A simple version of what I'm looking to get is this:

new_dict = {0:[4,2], 1:[5], 2:[1,3]}

For key 0, the order of numbers has switched because home ID 1L is farther along the road than 2L. This also means that 4 now pertains to 1L and 2 pertains to 2L.

I have some other issues, however, due to the way my dictionaries are separated. I'm looking for an approach that will the information together in one dictionary, so I can more easily keep track of which home number belongs to which home ID.

Ultimately, what I'm looking to achieve is this-- 1 is the index of a field I'm trying to update (with the new, sorted number):

final_dict = {1L:{1:4}, 2L:{1:2}, 3L:{1:5}, 4L:{1:1}, 5L:{1:3}}

A missing piece I just realized could be useful This creates a dictionary with a simple incrementation of the order of each home along the line. I think this belongs with my original question. :

another_dict = {0:[2,1], 1:[1], 2:[1,2]}

UPDATE I tried the following code using the following dictionaries, but things are still not sorting correctly. While the homes are sorted by distance and ready to be numbered sequentially, I am also looking to keep the set of existing numbers and switching them around to be in the right order based on distance. This code allows each home to keep their existing number regardless of distance order.

i_road_dict = {421: [32L, 33L, 34L], 422: [9L, 10L, 11L, 12L, 13L, 14L, 15L, 16L, 17L, 18L, 19L, 27L, 28L, 29L, 35L, 36L, 37L, 38L, 39L], 423: [66L, 67L, 72L, 73L, 76L], 623: [2L], 624: [0L], 627: [3L, 4L], 629: [86L], 317: [50L, 63L, 64L, 65L, 70L, 71L, 74L, 75L, 81L, 82L, 83L, 85L, 87L, 88L]}

i_num_dict = {421: [15, 19, 21], 422: [31, 33, 35, 39, 43, 31, 29, 25, 23, 19, 15, 41, 49, 47, 9, 7, 11, 13, 17], 423: [11, 13, 17, 23, 27], 623: [1], 624: [13], 627: [9, 5], 629: [7], 317: [109, 151, 45, 47, 143, 141, 133, 131, 101, 95, 91, 81, 57, 63]}

i_distance_dict = {0L: 61.488059367717, 2L: 8.021516228782936, 3L: 45.52003866488311, 4L: 25.20730241437668, 9L: 157.844303290623, 10L: 162.61477713824982, 11L: 177.70675687888885, 12L: 194.7672626115625, 13L: 205.85748324109224, 14L: 151.29798366856477, 15L: 147.66380499017282, 16L: 119.9462825595851, 17L: 114.98507682692828, 18L: 98.45714293590342, 19L: 87.46475300724273, 27L: 209.53486929892026, 28L: 232.3460547737345, 29L: 239.89698687340757, 32L: 71.13973224724995, 33L: 90.16514887960331, 34L: 106.48078486409304, 35L: 30.04092989941455, 36L: 39.961250890703326, 37L: 53.44419657185303, 38L: 83.59339524297145, 39L: 85.66697660333085, 50L: 549.0312971771257, 63L: 753.3816549180551, 64L: 225.80699058127138, 65L: 237.74936014259308, 66L: 58.12282403458027, 67L: 63.3770825337218, 70L: 708.6717387628081, 71L: 704.5817839747034, 72L: 87.27533124959758, 73L: 113.56828281454557, 74L: 658.1701619456403, 75L: 654.8787862943727, 76L: 137.46561448886376, 81L: 501.846856735727, 82L: 478.70973384256945, 83L: 456.2651041053348, 85L: 407.21753873616143, 86L: 34.367967658321774, 87L: 286.4419958357572, 88L: 317.3584642656698}

After using this code:

i_homes = []
for road_id, home_ids in i_road_dict.items():
    i_home_numbers_on_road = i_num_dict[road_id]
    for home_id, home_number in zip(home_ids, i_home_numbers_on_road):
        home = {}
        home['home_id'] = home_id
        home['home_number'] = home_number
        home['road_id'] = road_id
        home['distance'] = distance_dict[home_id]
        i_homes.append(home)

i_sorted_dict = {}
for road_id in i_road_dict:
    i_homes_on_road = [home for home in i_homes if home['road_id'] == road_id]
    i_ordered_homes = sorted(i_homes_on_road, key=lambda h: h['distance'])
    i_sorted_dict[road_id] = i_ordered_homes

I got this result:

i_sorted_dict = {421: [{'home_id': 32L, 'home_number': 15, 'road_id': 421, 'distance': 71.13973224724995}, {'home_id': 33L, 'home_number': 19, 'road_id': 421, 'distance': 90.16514887960331}, {'home_id': 34L, 'home_number': 21, 'road_id': 421, 'distance': 106.48078486409304}], 422: [{'home_id': 35L, 'home_number': 9, 'road_id': 422, 'distance': 30.04092989941455}, {'home_id': 36L, 'home_number': 7, 'road_id': 422, 'distance': 39.961250890703326}, {'home_id': 37L, 'home_number': 11, 'road_id': 422, 'distance': 53.44419657185303}, {'home_id': 38L, 'home_number': 13, 'road_id': 422, 'distance': 83.59339524297145}, {'home_id': 39L, 'home_number': 17, 'road_id': 422, 'distance': 85.66697660333085}, {'home_id': 19L, 'home_number': 15, 'road_id': 422, 'distance': 87.46475300724273}, {'home_id': 18L, 'home_number': 19, 'road_id': 422, 'distance': 98.45714293590342}, {'home_id': 17L, 'home_number': 23, 'road_id': 422, 'distance': 114.98507682692828}, {'home_id': 16L, 'home_number': 25, 'road_id': 422, 'distance': 119.9462825595851}, {'home_id': 15L, 'home_number': 29, 'road_id': 422, 'distance': 147.66380499017282}, {'home_id': 14L, 'home_number': 31, 'road_id': 422, 'distance': 151.29798366856477}, {'home_id': 9L, 'home_number': 31, 'road_id': 422, 'distance': 157.844303290623}, {'home_id': 10L, 'home_number': 33, 'road_id': 422, 'distance': 162.61477713824982}, {'home_id': 11L, 'home_number': 35, 'road_id': 422, 'distance': 177.70675687888885}, {'home_id': 12L, 'home_number': 39, 'road_id': 422, 'distance': 194.7672626115625}, {'home_id': 13L, 'home_number': 43, 'road_id': 422, 'distance': 205.85748324109224}, {'home_id': 27L, 'home_number': 41, 'road_id': 422, 'distance': 209.53486929892026}, {'home_id': 28L, 'home_number': 49, 'road_id': 422, 'distance': 232.3460547737345}, {'home_id': 29L, 'home_number': 47, 'road_id': 422, 'distance': 239.89698687340757}], 423: [{'home_id': 66L, 'home_number': 11, 'road_id': 423, 'distance': 58.12282403458027}, {'home_id': 67L, 'home_number': 13, 'road_id': 423, 'distance': 63.3770825337218}, {'home_id': 72L, 'home_number': 17, 'road_id': 423, 'distance': 87.27533124959758}, {'home_id': 73L, 'home_number': 23, 'road_id': 423, 'distance': 113.56828281454557}, {'home_id': 76L, 'home_number': 27, 'road_id': 423, 'distance': 137.46561448886376}], 623: [{'home_id': 2L, 'home_number': 1, 'road_id': 623, 'distance': 8.021516228782936}], 624: [{'home_id': 0L, 'home_number': 13, 'road_id': 624, 'distance': 61.488059367717}], 627: [{'home_id': 4L, 'home_number': 5, 'road_id': 627, 'distance': 25.20730241437668}, {'home_id': 3L, 'home_number': 9, 'road_id': 627, 'distance': 45.52003866488311}], 629: [{'home_id': 86L, 'home_number': 7, 'road_id': 629, 'distance': 34.367967658321774}], 317: [{'home_id': 64L, 'home_number': 45, 'road_id': 317, 'distance': 225.80699058127138}, {'home_id': 65L, 'home_number': 47, 'road_id': 317, 'distance': 237.74936014259308}, {'home_id': 87L, 'home_number': 57, 'road_id': 317, 'distance': 286.4419958357572}, {'home_id': 88L, 'home_number': 63, 'road_id': 317, 'distance': 317.3584642656698}, {'home_id': 85L, 'home_number': 81, 'road_id': 317, 'distance': 407.21753873616143}, {'home_id': 83L, 'home_number': 91, 'road_id': 317, 'distance': 456.2651041053348}, {'home_id': 82L, 'home_number': 95, 'road_id': 317, 'distance': 478.70973384256945}, {'home_id': 81L, 'home_number': 101, 'road_id': 317, 'distance': 501.846856735727}, {'home_id': 50L, 'home_number': 109, 'road_id': 317, 'distance': 549.0312971771257}, {'home_id': 75L, 'home_number': 131, 'road_id': 317, 'distance': 654.8787862943727}, {'home_id': 74L, 'home_number': 133, 'road_id': 317, 'distance': 658.1701619456403}, {'home_id': 71L, 'home_number': 141, 'road_id': 317, 'distance': 704.5817839747034}, {'home_id': 70L, 'home_number': 143, 'road_id': 317, 'distance': 708.6717387628081}, {'home_id': 63L, 'home_number': 151, 'road_id': 317, 'distance': 753.3816549180551}]}

At least for road 422, the homes are still out of order. I was expecting this (done by hand, so I hope I didn't miss anything) which switched the existing numbers around to sort them based on distance:

422: [{'home_id': 35L, 'home_number': 7, 'road_id': 422, 'distance': 30.04092989941455}, {'home_id': 36L, 'home_number': 9, 'road_id': 422, 'distance': 39.961250890703326}, {'home_id': 37L, 'home_number': 11, 'road_id': 422, 'distance': 53.44419657185303}, {'home_id': 38L, 'home_number': 13, 'road_id': 422, 'distance': 83.59339524297145}, {'home_id': 39L, 'home_number': 15, 'road_id': 422, 'distance': 85.66697660333085}, {'home_id': 19L, 'home_number': 17, 'road_id': 422, 'distance': 87.46475300724273}, {'home_id': 18L, 'home_number': 19, 'road_id': 422, 'distance': 98.45714293590342}, {'home_id': 17L, 'home_number': 23, 'road_id': 422, 'distance': 114.98507682692828}, {'home_id': 16L, 'home_number': 25, 'road_id': 422, 'distance': 119.9462825595851}, {'home_id': 15L, 'home_number': 29, 'road_id': 422, 'distance': 147.66380499017282}, {'home_id': 14L, 'home_number': 31, 'road_id': 422, 'distance': 151.29798366856477}, {'home_id': 9L, 'home_number': 31, 'road_id': 422, 'distance': 157.844303290623}, {'home_id': 10L, 'home_number': 33, 'road_id': 422, 'distance': 162.61477713824982}, {'home_id': 11L, 'home_number': 35, 'road_id': 422, 'distance': 177.70675687888885}, {'home_id': 12L, 'home_number': 39, 'road_id': 422, 'distance': 194.7672626115625}, {'home_id': 13L, 'home_number': 41, 'road_id': 422, 'distance': 205.85748324109224}, {'home_id': 27L, 'home_number': 43, 'road_id': 422, 'distance': 209.53486929892026}, {'home_id': 28L, 'home_number': 47, 'road_id': 422, 'distance': 232.3460547737345}, {'home_id': 29L, 'home_number': 49, 'road_id': 422, 'distance': 239.89698687340757}]

another update The issue was with the creation of final_dict as the answer provides. I adapted the sort to the new numbers and zipped with the the ordered homes instead of "homes_on_road":

i_final_dict = {}
for road_id in i_road_dict:
    i_homes_on_road = [home for home in i_homes if home['road_id'] == road_id]
    i_ordered_homes = sorted(i_homes_on_road, key=lambda h: h['distance'])
    #i_ordered_nums = [home['home_number'] for home in i_ordered_homes]
    i_ordered_nums = sorted([home['home_number'] for home in i_ordered_homes])
    for home, new_number in zip(i_ordered_homes, i_ordered_nums):
        i_final_dict[home['home_id']] = {sort_num_idx:new_number}

Upvotes: 1

Views: 304

Answers (2)

TessellatingHeckler
TessellatingHeckler

Reputation: 29013

Does it have to be that terse? How about making a dictionary per home, with all the related information and putting those in a list:

from pprint import pprint

road_dict = {0:[1L,2L], 1:[3L], 2:[4L,5L]} # road_id:home_id
dist_dict = {1L: 4.1, 2L: 2.1, 3L: 4, 4L: 2.1, 5L: 6} # home_id:distance
num_dict = {0:[2,4], 1:[5], 2:[1,3]} # road_id:[house_numbers]

homes = []
for road_id, home_ids in road_dict.items():
    home_numbers_on_road = num_dict[road_id]

    for home_id, home_number in zip(home_ids, home_numbers_on_road):
        home = {'home_id':     home_id,
                'home_number': home_number,
                'road_id':     road_id,
                'distance':    dist_dict[home_id]}

        homes.append(home)

pprint(homes)

Gives a list, with a dictionary for each home, keeping all the things together:

[{'distance': 4.1, 'home_id': 1L, 'home_number': 2, 'road_id': 0},
 {'distance': 2.1, 'home_id': 2L, 'home_number': 4, 'road_id': 0},
 {'distance': 4, 'home_id': 3L, 'home_number': 5, 'road_id': 1},
 {'distance': 2.1, 'home_id': 4L, 'home_number': 1, 'road_id': 2},
 {'distance': 6, 'home_id': 5L, 'home_number': 3, 'road_id': 2}]

And then you get a much easier time of building things out of it:

new_dict = {}
for road_id in road_dict:
    homes_on_road = [home for home in homes if home['road_id'] == road_id]
    ordered_homes = sorted(homes_on_road, key=lambda h: h['distance'])
    new_dict[road_id] = ordered_homes


pprint(new_dict)

Gives:

{0: [{'distance': 2.1, 'home_id': 2L, 'home_number': 4, 'road_id': 0},
     {'distance': 4.1, 'home_id': 1L, 'home_number': 2, 'road_id': 0}],
 1: [{'distance': 4, 'home_id': 3L, 'home_number': 5, 'road_id': 1}],
 2: [{'distance': 2.1, 'home_id': 4L, 'home_number': 1, 'road_id': 2},
     {'distance': 6, 'home_id': 5L, 'home_number': 3, 'road_id': 2}]}

Which is your 0:4,2, 1:5, 2:1,3 intermediate result.

Although this has reordered the homes and not renumbered them. But then what does it mean to renumber home 5 on street 2, when it's the only home on street 2? Assuming they go 1, 2... on each street:

new_dict = {}
for road_id in road_dict:
    homes_on_road = [home for home in homes if home['road_id'] == road_id]
    ordered_homes = sorted(homes_on_road, key=lambda h: h['distance'])
    for position, home in enumerate(ordered_homes):
        home['home_number'] = position + 1

    new_dict[road_id] = ordered_homes

pprint(new_dict)

Which gives:

{0: [{'distance': 2.1, 'home_id': 2L, 'home_number': 1, 'road_id': 0},
     {'distance': 4.1, 'home_id': 1L, 'home_number': 2, 'road_id': 0}],
 1: [{'distance': 4, 'home_id': 3L, 'home_number': 1, 'road_id': 1}],
 2: [{'distance': 2.1, 'home_id': 4L, 'home_number': 1, 'road_id': 2},
     {'distance': 6, 'home_id': 5L, 'home_number': 2, 'road_id': 2}]}

Which has put the houses to show in the order they are physically in (by distance), and renumbered them sequentially from closest to furthest on a road-by-road basis.

[Edit: maybe correction]

Edit: Is this what the final_dict should be?

# order the homes by distance
# pair up the homes by position with the home_numbers by distance

final_dict = {}
for road_id in road_dict:
    homes_on_road = [home for home in homes if home['road_id'] == road_id]
    ordered_homes = sorted(homes_on_road, key=lambda h: h['distance'])
    ordered_nums = [home['home_number'] for home in ordered_homes]

    for home, new_number in zip(homes_on_road, ordered_nums):
        final_dict[home['home_id']] = {1:new_number}

pprint(final_dict)

Giving:

{1L: {1: 4}, 2L: {1: 2}, 3L: {1: 5}, 4L: {1: 1}, 5L: {1: 3}}

Upvotes: 1

Blair
Blair

Reputation: 6693

Making new_dict:

>>> new_dict = dict()
>>> for ikey in road_dict:
        l = list(sorted(num_dict[ikey],key = lambda x:dist_dict[road_dict[ikey][num_dict[ikey].index(x)]]))
        print l
>>> for ikey in road_dict:
        l = list(sorted(num_dict[ikey],key = lambda x:dist_dict[road_dict[ikey][num_dict[ikey].index(x)]]))
        new_dict[ikey] = l


>>> new_dict
{0: [4, 2], 1: [5], 2: [1, 3]}

Making final_dict:

>>> x = 'x'
>>> for ikey in road_dict:
        for j in range(len(road_dict[ikey])):
            final_dict[road_dict[ikey][j]] = {x : new_dict[ikey][j]}


>>> final_dict
{1L: {'x': 4}, 2L: {'x': 2}, 3L: {'x': 5}, 4L: {'x': 1}, 5L: {'x': 3}}

I hope this works for you!

Upvotes: 1

Related Questions