2

I want to create a dictionary using an iterable which has multiple iterables in itself as well.

I tried:

def setdict(list = ["hello", "world", "something", "foo"])
    for i in list:
        dict = {i[0]:i}
    return dict
print setdict(list = ["hello", "world", "something", "foo"])

I expect an output like:

{"h":"hello", "w":"world", "s":"something", "f":"foo"}

but the actual output is:

{'f': 'foo'}
Patrick Artner
  • 50,409
  • 9
  • 43
  • 69
explorer
  • 31
  • 1
  • 6

3 Answers3

3

Using a dict comprehension

Ex:

def setdict(lst = ["hello", "world", "something", "foo"]):
    return {i[0]:i for i in lst}
print setdict(lst = ["hello", "world", "something", "foo"])

Output:

{'h': 'hello', 's': 'something', 'w': 'world', 'f': 'foo'}

In your case you are over-writing the dictionary in each loop.

Rakesh
  • 81,458
  • 17
  • 76
  • 113
  • 1
    While the input list isn't being modified in this case, it may be helpful for a beginner to point out that [mutable default arguments](https://docs.python-guide.org/writing/gotchas/#mutable-default-arguments) can be dangerous as well – Brad Solomon Jan 04 '19 at 12:32
3

Here:

dict = {i[0]:i}

you are creating a new dictionary each time.

Declare it first and then update:

result = {}
for i in items:
    result[i[0]] = i
return result

The comprehension given by the other answer is also good.

By the way, you shouldn't use dict or list as variable names. It's a built-in word, so you will break your program in mysterious ways.

Using a list as a default argument will also lead to awful surprising errors

  • Yes, the code is not directly from my program; I am aware of the fact that built-in names should not be used as variable names or parameters. Thanks for your answer. – explorer Jan 04 '19 at 12:42
2

Your for-loop recreates the whole dict() on every iteration: dict = {i[0]:i} -leaving you with the last value.

Your (working) implementation would make this

print setdict(["hello", "world", "something", "foo", "hello - 2"])

to

{"h":"hello - 2", "w":"world", "s":"something", "f":"foo"}

loosing the first "hello".


It may be better to use a defaultdict to avoid overwriting duplicates:

from collections import defaultdict

def setdict(l): # dont do l = []  - it has ramifications
    d = defaultdict(list)
    for i in l:
        d[i[0]].append(i)

    return dict(d)

print setdict(["hello", "world", "something", "foo", "hello - 2"])

Output:

{'h': ['hello', 'hello - 2'], 's': ['something'], 'w': ['world'], 'f': ['foo']}

Other remarks & ramifications:

  • do not call variables after built ins - they shadow them:

    k = str(5)
    str = 22
    o = str(5)  # crash - the str-function is shadowed
    
  • avoid default params that are references:

def k(l=[]): # reference default param, keeps values
    l.append(0)         # over different calls of the function
        return l 

    print(k())
    print(k())
    print(k())
    print(k())
    print(k())
[0]
[0, 0]
[0, 0, 0]
[0, 0, 0, 0]
[0, 0, 0, 0, 0]

See "Least Astonishment" and the Mutable Default Argument

Patrick Artner
  • 50,409
  • 9
  • 43
  • 69