Append to list in a dictionary after setdefault

15,030

Solution 1

The list.append is an in-place operation. So it just modifies the list object and doesn't return anything. That is why, by default, None is getting returned from list.append and you are storing that corresponding to the key in this line

hash_table[elem] = hash_table[elem].append(1)

In your case, you don't need the if condition at all.

def test(Ar):
    hash_table = {}
    for elem in Ar:
        hash_table.setdefault(elem, []).append(1)
    print(hash_table)

because, setdefault will first look for the key elem in it and it found something, then it will return the value corresponding to it. And if it doesn't then it will create key elem and use the second argument passed to it as the value and then return then value.


Instead of using this, you can use collections.defaultdict, like this

from collections import defaultdict
def test(Ar):
    hash_table = defaultdict(list)
    for elem in Ar:
        hash_table[elem].append(1)
    print(hash_table)

This would do almost the same thing as the setdefault version


It looks like you are trying to find the frequency of elements. In that case you can simply use collections.Counter

from collections import Counter
Ar = (1, 2, 3, 4, 5, 1, 2)
print Counter(Ar)
# Counter({1: 2, 2: 2, 3: 1, 4: 1, 5: 1})

This will give the number of times each and every element occurred in the iterable passed.

Solution 2

The bug is in this line:

hash_table[elem] = hash_table[elem].append(1)

list.append(x) returns None, which you are assigning to hash_table[elem]

The else part is unnecessary, but still for getting correct results, remove the assignment in the else part.


Note that the None is only for elements that occur twice. If any element existed thrice, you'd have gotten an error.

Share:
15,030
KurinchiMalar
Author by

KurinchiMalar

Updated on June 11, 2022

Comments

  • KurinchiMalar
    KurinchiMalar almost 2 years

    I have the below code where I am trying to append a 1 to the hash of an element, on every occurence of it in input.

    def test(Ar):
        hash_table = {}
        for elem in Ar:
            if elem not in hash_table:
                hash_table.setdefault(elem,[]).append(1)
            else:
                hash_table[elem] = hash_table[elem].append(1)
        print(hash_table)
    
    Ar = (1,2,3,4,5,1,2)
    test(Ar)
    

    Output:

    {1: None, 2: None, 3: [1], 4: [1], 5: [1]}
    

    Expected Output:

    {1: [1,1], 2: [1,1], 3: [1], 4: [1], 5: [1]}
    

    I am puzzled why None gets in on doing an append. Kindly explain what is happening.

    Note:

    On typing the else portion,

    hash_table[elem] = hash_table[elem].append(1) # the append() was not suggested at all by the IDE. I forcibly put it, hoping things will work.
    
  • mgilson
    mgilson over 8 years
    Also note that defaultdict have a default_factory property, which when set to None makes the default dict behave like a regular dict once again. This is particularly useful for functions which want to construct a dictionary using defaultdict behaviors, but then want to return something that behaves like a regular dict.