-1

I have a data structure

  • I have two functions
  • One function return the id
  • second function return the length

I am successfully added to list with below code

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]
def id_extract(data):
    total = []
    cur_count = {"count": length(data)}
    total.append(cur_count)
    for i in data:
        j = {"id": i["id"]}
        total.append(j)
    return total
def length(data):
    return(len(data))

id_extract(data) 

But if I need to update to dictionary I am getting error.

Sample json is below. If I need to add in to a dictionary, I tried with below code. I got error:

UnboundLocalError: local variable 'total' referenced before assignment
data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]
def id_extract(data):
    myDict = {} 
    myDict.update( {'values': total} ) 
    cur_count = {"count": length(data)}
    total = []
    for i in data:
        j = {"id": i["id"]}
        total.append(j)
    return myDict

def length(data):
    return(len(data))

id_extract(data)

My expected out is

{'count': 3,'values' : [{'id': 1}, {'id': 2}, {'id': 3}]}
quamrana
  • 37,849
  • 12
  • 53
  • 71
  • 1
    This line `myDict.update( {'values': total} ) ` references `total`, which hasn't yet been assigned a value. – CryptoFool Oct 06 '20 at 15:21
  • Voting to close as typo: fixing the `total` bug gives `{'values': [{'id': 1}, {'id': 2}, {'id': 3}]}`. You can figure out how to add `'count': 3` – Pranav Hosangadi Oct 06 '20 at 15:24
  • [How to debug small programs.](https://ericlippert.com/2014/03/05/how-to-debug-small-programs/) | [What is a debugger and how can it help me diagnose problems?](https://stackoverflow.com/q/25385173/843953) Your error even _tells you exactly what's wrong_: **local variable 'total' referenced before assignment** – Pranav Hosangadi Oct 06 '20 at 15:26

4 Answers4

1

I would like to show you what is the problem, how you can solve it and how we can improve the solution.

Your code works if you put the line where you initialize the total variable before you use it.
In your version you are using it before it is instantiated and that is why you get the UnboundLocalError: local variable 'total' referenced before assignment error.

Here's the fix, once done it is easy to manipulate the result dictionary in order to add to it the "count" field containing the length:

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]

def id_extract(data):
    total = [] # I put the total variable initialization before its usage
    myDict = {} 
    myDict.update( {'values': total} ) 
    cur_count = {"count": len(data)}
    for i in data:
        j = {"id": i["id"]}
        total.append(j) # As explained total must be initialized BEFORE we use it here
    result = {}
    result['count'] = len(data)
    result['values'] = myDict['values']
    return result
    
print(id_extract(data))

The code works as expected.
Can we improve it, what looks off? Why two dictionaries, for example?
I would suggest to optimize it simply putting data into your result dictionary directly:

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]

def id_extract(data):
    result = {'count': len(data), 'values' : []} 
    for i in data:
        result['values'].append({"id": i["id"]})
    return result

print(id_extract(data))

Already better, right?
We can improve it even more using the power of Python's List Comprehensions:

List comprehensions provide a concise way to create lists. Common applications are to make new lists where each element is the result of some operations applied to each member of another sequence or iterable, or to create a subsequence of those elements that satisfy a certain condition.

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]

def id_extract(data):
    result = {'count': len(data)} 
    result['values'] = [{"id": item["id"]} for item in data] 
return result

print(id_extract(data))

At this point we keep on optimizing following the same techniques we used so far and we get the function in its final (well, for me :) ) form:

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]

def id_extract(data):
    return {'count': len(data), 'values' : [{"id": item["id"]} for item in data]} 

print(id_extract(data))

Output

{'count': 3, 'values': [{'id': 1}, {'id': 2}, {'id': 3}]}
Pitto
  • 8,229
  • 3
  • 42
  • 51
1

Corrected code. You assigned total before initialization.

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]
def id_extract(data):
    total = [] 
    for i in data:
        j = {"id": i["id"]}
        total.append(j)
    return {'count': len(data), 'values': total}

id_extract(data)
amsh
  • 3,097
  • 2
  • 12
  • 26
0

You can use defaultdict which is built-in python library to create a dict of list. Then replace the count key list value with a number

An example of creating default dict is dict_of_list = defaultdict(list)

To add a value to the key: dict_of_list[value].append(some_val)

dtlam26
  • 1,410
  • 11
  • 19
0

Many good answers, but you can inline the whole thing:

data = [{"id":1,"name":"a"},{"id":2,"name":"b"},{"id":3,"name":"c"}]

extract = {'count': len(data), 'values': [{"id": i["id"]} for i in data]}
quamrana
  • 37,849
  • 12
  • 53
  • 71