Home > other >  Python dictionary - Copy and flip values
Python dictionary - Copy and flip values

Time:01-27

How to check if a key of multiple dictionary is the same and if it is copy the value and paste it to a new value but flipped.

dicts = [
{'A':1, 'B':2, 'C':10, 'D':100, 'E':None},
{'A':2, 'B':3, 'C':10, 'D':200, 'E':None},
{'A':3, 'B':4, 'C':20, 'D':300, 'E':None},
{'A':4, 'B':5, 'C':20, 'D':400, 'E':None},
{'A':5, 'B':6, 'C':30, 'D':500, 'E':None},
{'A':6, 'B':7, 'C':30, 'D':600, 'E':None}]

for x in dicts:
  for y in dicts:
    if y['C'] == x['C']:
       # do something and flip the A value as below and copy it to E
  print(dicts)
[{'A':1, 'B':2, 'C':10, 'D':100, 'E':2},
{'A':2, 'B':3, 'C':10, 'D':200, 'E':1},
{'A':3, 'B':4, 'C':20, 'D':300, 'E':4},
{'A':4, 'B':5, 'C':20, 'D':400, 'E':3},
{'A':5, 'B':6, 'C':30, 'D':500, 'E':7},
{'A':6, 'B':7, 'C':30, 'D':600, 'E':6}]

If there's just one match, just copy the value from A to E.

CodePudding user response:

You can solve this in linear time (i.e. not using a double loop) by keeping references to the found matches.

I am assuming here that there is a maximum of 2 matches per C:

dicts = [
{'A':1, 'B':2, 'C':10, 'D':100, 'E':None},
{'A':2, 'B':3, 'C':10, 'D':200, 'E':None},
{'A':3, 'B':4, 'C':20, 'D':300, 'E':None},
{'A':4, 'B':5, 'C':20, 'D':400, 'E':None},
{'A':5, 'B':6, 'C':30, 'D':500, 'E':None},
{'A':6, 'B':7, 'C':30, 'D':600, 'E':None}]

refs = {}

for i, d in enumerate(dicts):
    if d['C'] in refs:    # we already found the first match
        j = refs[d['C']]
        # swap the values
        dicts[j]['E'], dicts[i]['E'] = dicts[i]['A'], dicts[j]['A']
    else:                 # this is the first match
        refs[d['C']] = i  # keep a reference of the index
        # copy A to E in case of a single match
        d['E'] = d['A']

dicts

output:

[{'A': 1, 'B': 2, 'C': 10, 'D': 100, 'E': 2},
 {'A': 2, 'B': 3, 'C': 10, 'D': 200, 'E': 1},
 {'A': 3, 'B': 4, 'C': 20, 'D': 300, 'E': 4},
 {'A': 4, 'B': 5, 'C': 20, 'D': 400, 'E': 3},
 {'A': 5, 'B': 6, 'C': 30, 'D': 500, 'E': 6},
 {'A': 6, 'B': 7, 'C': 30, 'D': 600, 'E': 5}]

CodePudding user response:

if there are always 2 possile duplicate of 'C' you can just make sure that x and y is different and then assign 'E':

dicts = [
{'A':1, 'B':2, 'C':10, 'D':100, 'E':None},
{'A':2, 'B':3, 'C':10, 'D':200, 'E':None},
{'A':3, 'B':4, 'C':20, 'D':300, 'E':None},
{'A':4, 'B':5, 'C':20, 'D':400, 'E':None},
{'A':5, 'B':6, 'C':30, 'D':500, 'E':None},
{'A':6, 'B':7, 'C':30, 'D':600, 'E':None}]
for x in dicts:
  for y in dicts:
    if y['C'] == x['C'] and y is not x:
        x['E'] = y['A']
        y['E'] = x['A']
print(dicts)

Output:

[{'A': 1, 'B': 2, 'C': 10, 'D': 100, 'E': 2},
 {'A': 2, 'B': 3, 'C': 10, 'D': 200, 'E': 1},
 {'A': 3, 'B': 4, 'C': 20, 'D': 300, 'E': 4},
 {'A': 4, 'B': 5, 'C': 20, 'D': 400, 'E': 3},
 {'A': 5, 'B': 6, 'C': 30, 'D': 500, 'E': 6},
 {'A': 6, 'B': 7, 'C': 30, 'D': 600, 'E': 5}]

CodePudding user response:

Use itertools.combinations to loop over your dicts:

import itertools

dicts = [
{'A':1, 'B':2, 'C':10, 'D':100, 'E':None},
{'A':2, 'B':3, 'C':10, 'D':200, 'E':None},
{'A':3, 'B':4, 'C':20, 'D':300, 'E':None},
{'A':4, 'B':5, 'C':20, 'D':400, 'E':None},
{'A':5, 'B':6, 'C':30, 'D':500, 'E':None},
{'A':6, 'B':7, 'C':30, 'D':600, 'E':None}]

for x, y in itertools.combinations(dicts, 2):
    if x['E'] is None: # skip if already set
        if x['C'] == y['C']:
            x['E'] = y['A']
            y['E'] = x['A']

This works because there is only ever one matching pair in the example dicts. In case there is not, you should specify how to handle that case.

CodePudding user response:

Beware of the BigO : your 2 nested for loops equal to O(n^2).
You can reduce it with an hashtable.

dicts = [
    {"A": 1, "B": 2, "C": 10, "D": 100, "E": None},
    {"A": 2, "B": 3, "C": 10, "D": 200, "E": None},
    {"A": 3, "B": 4, "C": 20, "D": 300, "E": None},
    {"A": 4, "B": 5, "C": 20, "D": 400, "E": None},
    {"A": 5, "B": 6, "C": 30, "D": 500, "E": None},
    {"A": 6, "B": 7, "C": 30, "D": 600, "E": None},
]

c = {}

for i in range(len(dicts)):
    if not c.get(dicts[i]["C"]):
        c.update({dicts[i]["C"]: {"upper_row": i}})
    else:
        c[dicts[i]["C"]].update({"lower_row": i})

print(dicts)
print(c)

for value, duplicates in c.items():
    lower = duplicates.get("lower_row")
    if duplicates.get("lower_row"):
        upper = duplicates.get("upper_row")
        dicts[upper]["E"] = dicts[lower]["A"]
        dicts[lower]["E"] = dicts[upper]["A"]

print(dicts)

Output :

"""
Original state of dicts :

[
{'A': 1, 'B': 2, 'C': 10, 'D': 100, 'E': None},
{'A': 2, 'B': 3, 'C': 10, 'D': 200, 'E': None},
{'A': 3, 'B': 4, 'C': 20, 'D': 300, 'E': None},
{'A': 4, 'B': 5, 'C': 20, 'D': 400, 'E': None},
{'A': 5, 'B': 6, 'C': 30, 'D': 500, 'E': None},
{'A': 6, 'B': 7, 'C': 30, 'D': 600, 'E': None}]

c hashtable :

{10: {'upper_row': 0, 'lower_row': 1}, 20: {'upper_row': 2, 'lower_row': 3}, 30: {'upper_row': 4, 'lower_row': 5}}

Final state of dicts: 

[
{'A': 1, 'B': 2, 'C': 10, 'D': 100, 'E': 2}, 
{'A': 2, 'B': 3, 'C': 10, 'D': 200, 'E': 1},
{'A': 3, 'B': 4, 'C': 20, 'D': 300, 'E': 4},
{'A': 4, 'B': 5, 'C': 20, 'D': 400, 'E': 3},
{'A': 5, 'B': 6, 'C': 30, 'D': 500, 'E': 6},
{'A': 6, 'B': 7, 'C': 30, 'D': 600, 'E': 5}]
"""
  •  Tags:  
  • Related