2
import random

data_bid = {}
n = 2
uniq_no = random.randint(101, 1000)
print(f"Bid NO. :{uniq_no} ")
name = input("Name: ")
phone = input("Phone Number: ")
while len(phone) != 10:
    print("<<<<<<-----------Please Enter Valid Data---------->>>>>>")
    phone = input("Phone Number: ")
bid_amount = float(input("Enter The Bid amount $: "))

for num in range(1, n):
    data_bid[f"{uniq_no}"]["name"] = name
    data_bid[f"{uniq_no}"]["phone"] = phone
    data_bid[f"{uniq_no}"]["bid amount"] = bid_amount

when I run the code I get KeyError: '553'

I'm unable to resolve it and I want to store my data

data_bid = {"uniq_no" ={"name" = name, "phone" = phone}}

I want to store data in a nested dictionary.

Craig
  • 4,605
  • 1
  • 18
  • 28
Shivam Pandey
  • 83
  • 2
  • 8

3 Answers3

2

In order to have a nested dictionary, you need each new uniq_no to have a dictionary initialized as it's value. You can achive this by initializing a dictionary for each new uniq_no:

data_bid[uniq_no] = {}

However, the pythonic way to do this is by using defaultdict:

import random
from collections import defaultdict
data_bid = defaultdict(dict)
n = 2
uniq_no = random.randint(101, 1000)
print(f"Bid NO. :{uniq_no} ")
name = input("Name: ")
phone = input("Phone Number: ")
while len(phone) != 10:
    print("<<<<<<-----------Please Enter Valid Data---------->>>>>>")
    phone = input("Phone Number: ")
bid_amount = float(input("Enter The Bid amount $: "))

for num in range(1, n):
    data_bid[uniq_no]["name"] = name
    data_bid[uniq_no]["phone"] = phone
    data_bid[uniq_no]["bid amount"] = bid_amount

Quoting python's documentation:

A defaultdict returns a new dictionary-like object. defaultdict is a subclass of the built-in dict class. It overrides one method and adds one writable instance variable. The remaining functionality is the same as for the dict.

In addition, I didn't understand why setting the dictionary key as a string. You can use the original integer value.

  • To ask a question based on your answer, if i have a million rows, that were pulled from a db, and need this dict build; when it comes to performance, is using `defaultdict` faster than say ```data_bid[uniq_no] = { 'name': name, 'phone': phone, 'bid_amount': bid_amount }``` – Anu Dec 24 '21 at 17:00
  • @Anu Good question, my first guess was that both perform the same in the case you described - as `defaultdict` is a subclass of the `dict` class that essentialy receives a function that returns the default value of new keys in the dictionary. However, reading this: https://realpython.com/python-defaultdict/ it actually seems that `defaultdict` is faster than `dict`. –  Dec 24 '21 at 22:21
  • I was curious, so i can ran a quick test. replaced n with 10M and used random to fill in the the name, phone, and bid data. the only change in code was one using defaultdict, and the other just initializing a new dict using {}. The one with defaultdict took 44s, and the one with {} took 42s. Ran a second test with n 30M defaultdict took 2:16s and {} took 2:10s so it looks like defaultdict is fractionally slower with really large data sets. I wonder if this would still translate, if the dicts were more complex. – Anu Dec 25 '21 at 03:22
0

You need to initialize your nested dictionary too. Otherwise, when you try to set a value on the nested dictionary it will throw an error.

I'm not sure why are you setting the dictionary key as string. Did you notice that you can use the integer directly?

import random

data_bid = {}
n = 2
uniq_no = random.randint(101, 1000)
data_bid[uniq_no] = {} # create the nested dictionary 
print(f"Bid NO. :{uniq_no} ")
name = input("Name: ")
phone = input("Phone Number: ")
while len(phone) != 10:
    print("<<<<<<-----------Please Enter Valid Data---------->>>>>>")
    phone = input("Phone Number: ")
bid_amount = float(input("Enter The Bid amount $: "))

for num in range(1, n):
    data_bid[uniq_no]["name"] = name # Save the values on the nested dictionary
    data_bid[uniq_no]["phone"] = phone
    data_bid[uniq_no]["bid amount"] = bid_amount

Of course, you can keep the f"{uniq_no}" and use an string instead a int

...
data_bid[f"{uniq_no}"] = {}

...

for num in range(1, n):
    data_bid[f"{uniq_no}"]["name"] = name
    data_bid[f"{uniq_no}"]["phone"] = phone
    data_bid[f"{uniq_no}"]["bid amount"] = bid_amount
Latra
  • 492
  • 3
  • 14
0

I agree with @eyal-golan and would probably use collections.defaultdict(dict) myself, I thought though that I would show a simple alternative using setdefault(). It is a one line addition to your current code:

import random

data_bid = {}
n = 2
uniq_no = random.randint(101, 1000)
print(f"Bid NO. :{uniq_no} ")
name = input("Name: ")
phone = input("Phone Number: ")
while len(phone) != 10:
    print("<<<<<<-----------Please Enter Valid Data---------->>>>>>")
    phone = input("Phone Number: ")
bid_amount = float(input("Enter The Bid amount $: "))

## ---------------------------
## if this key is not in the dictionary add it with a value of an
## empty dictionary.
## ---------------------------
data_bid.setdefault(f"{uniq_no}", {})
## ---------------------------

for num in range(1, n):
    data_bid[f"{uniq_no}"]["name"] = name
    data_bid[f"{uniq_no}"]["phone"] = phone
    data_bid[f"{uniq_no}"]["bid amount"] = bid_amount

print(data_bid)
JonSG
  • 10,542
  • 2
  • 25
  • 36