1

I have a list that looks like this

[
    {'name': 'a', 'value': 'x'},
    {'name': 'a', 'value': 'x'},
    {'name': 'a', 'value': 'x'},
    {'name': 'b', 'value': 'x'},
    {'name': 'b', 'value': 'x'},
    {'name': 'c', 'value': 'x'}
]

I want to convert it into a dictionary that looks like this

{
    'a-0': 'x',
    'a-1': 'x',
    'a-2': 'x',
    'b-0': 'x',
    'b-1': 'x',
    'c':   'x'
}

So for any duplicated name I want to append an index to the end of all instances, but if the name isn't duplicated than it should just be left.

I have written a function to do this but I don't think it is very efficient or generally pleasant.

def transform(mylist):
    names = [x['name'] for x in mylist]
    duplicates = {x: 0 for x in names if names.count(x) > 1}
    out = {}
    for row in mylist:
        key = row['name']
        value = row['value']
        if key in duplicates:
            newkey = "{key}-{index}".format(key=key, index=duplicates[key])
            duplicates[key] = duplicates[key] + 1
        else:
            newkey = key
        out[newkey] = value
    return out

Is there a better way to do this?

Jacob Tomlinson
  • 3,341
  • 2
  • 31
  • 62

2 Answers2

2

You could do:

lst = [
    {'name': 'a', 'value': 'x'},
    {'name': 'a', 'value': 'x'},
    {'name': 'a', 'value': 'x'},
    {'name': 'b', 'value': 'x'},
    {'name': 'b', 'value': 'x'},
    {'name': 'c', 'value': 'x'}
]

d = {}
for e in lst:
    d.setdefault(e['name'], []).append(e['value'])

result = {}
for key, values in d.items():
    if len(values) > 1:
        for i, value in enumerate(values):
            result[f'{key}-{i}'] = value
    else:
        result[key] = values[0]

print(result)

Output

{'a-0': 'x', 'a-1': 'x', 'a-2': 'x', 'b-0': 'x', 'b-1': 'x', 'c': 'x'}
Dani Mesejo
  • 61,499
  • 6
  • 49
  • 76
1

It can be done in two loops. For example, the first uses the same rule for all keys, the second fixes single values. If inp is the input list:

from collections import Counter

cnt = Counter()
res = dict()
# First create keys with number
for o in inp:
    new_key = o["name"] + "-" + str(cnt[o["name"]])
    res[new_key] = o["value"]
    cnt[o["name"])] += 1

# Then fix single keys
for name, n in cnt.items():
    if n == 1:
        key = f"{name}-0"
        value = res[key]
        del res[key]
        res[name] = value

res
> {'a-0': 'x', 'a-1': 'x', 'a-2': 'x', 'b-0': 'x', 'b-1': 'x', 'c': 'x'}
koPytok
  • 3,453
  • 1
  • 14
  • 29