DerDressing
DerDressing

Reputation: 315

Delete dict elements by index list

I have a dict with different keys of the same length:

list_in_dict = list(range(0, 10))
test_dict = {"A" : list_in_dict , "B": list_in_dict , "C": list_in_dict}

Then I have a list with indices like this:

delete_index_list = [1,5,7]

I want to delete all elements in the keys, where the position corresponds to the index.

I tried this (but it totally fails):

for i in range(len(delete_index_list)):
    del(test_dict["A"][delete_index_list[i]])
    del(test_dict["B"][delete_index_list[i]])
    del(test_dict["C"][delete_index_list[i]])

Possibly I have to use list comprehension here? What would be the most compact way to achieve this result:

test_dict 
Out: 
{'A': [0, 2, 3, 4, 6, 8, 9],
 'B': [0, 2, 3, 4, 6, 8, 9],
 'C': [0, 2, 3, 4, 6, 8, 9]}

Upvotes: 1

Views: 1668

Answers (2)

Alexandre B.
Alexandre B.

Reputation: 5500

You can try dict and list comprehension:

{k:[elt for ind, elt in enumerate(v) if ind not in delete_index_list] for k,v in test_dict.items() }

Full code:

# Build data
list_in_dict = list(range(0, 10))
test_dict = {"A" : list_in_dict , "B": list_in_dict , "C": list_in_dict}

# Index to remve
delete_index_list = [1,5,7]

out = {k:[elt for ind, elt in enumerate(v) if ind not in delete_index_list] for k,v in test_dict.items() }
print(out)
# {'A': [0, 2, 3, 4, 6, 8, 9],
#  'B': [0, 2, 3, 4, 6, 8, 9],
#  'C': [0, 2, 3, 4, 6, 8, 9]}

Upvotes: 1

glibdud
glibdud

Reputation: 7880

The main issue with your approach is that once you remove index 1, what was previously at index 5 is now actually at 4. If the items in delete_items_list are sorted, you can get around that by starting at the end of the list and working your way back toward the beginning. (It's also unnecessary to mess with the indices of delete_items_list... that didn't cause a problem, but I've fixed it here to help with code readability.)

for i in reversed(delete_index_list):
    del(test_dict["A"][i])
    del(test_dict["B"][i])
    del(test_dict["C"][i])

You can be a little less repetitive by adding another for loop:

for k in test_dict:
    for i in reversed(delete_index_list):
        del(test_dict[k][i])

As suggested in another answer, if rebuilding the lists in test_dict is ok, that can be done with comprehensions. In order to properly remove indices and not values, you'll need to use enumerate():

test_dict = {k : [val for i, val in enumerate(v) if i not in delete_index_list] for (k, v) in test_dict.items()}

Upvotes: 2

Related Questions