Check if All Values Exist as Keys in Dictionary

I have a list of values, and a dictionary. I want to ensure that each value in the list exists as a key in the dictionary. At the moment I’m using two sets to figure out if any values don’t exist in the dictionary

unmapped = set(foo) - set(bar.keys())

Is there a more pythonic way to test this though? It feels like a bit of a hack?

Solution:

Your approach will work, however, there will be overhead from the conversion to set.

Another solution with the same time complexity would be:

all(i in bar for i in foo)

Both of these have time complexity O(len(foo))

bar = {str(i): i for i in range(100000)}
foo = [str(i) for i in range(1, 10000, 2)]

%timeit all(i in bar for i in foo)
462 µs ± 14.8 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

%timeit set(foo) - set(bar)
14.6 ms ± 174 µs per loop (mean ± std. dev. of 7 runs, 100 loops each)

# The overhead is all the difference here:

foo = set(foo)
bar = set(bar)

%timeit foo - bar
213 µs ± 1.48 µs per loop (mean ± std. dev. of 7 runs, 1000 loops each)

The overhead here makes a pretty big difference, so I would choose all here.

Advertisements

IndentationError: unexpected indent after comment

I am trying to write some Python example code with a line commented out:

user_by_email = session.query(User)\
    .filter(Address.email=='one')\
    #.options(joinedload(User.addresses))\
    .first()

I also tried:

user_by_email = session.query(User)\
    .filter(Address.email=='one')\
#    .options(joinedload(User.addresses))\
    .first()

But I get IndentationError: unexpected indent.
If I remove the commented out line, the code works.
I am decently sure that I use only spaces (Notepad++ screenshot):

enter image description here

Solution:

Enclose the statement in paranthesis

user_by_email = (session.query(User)
     .filter(Address.email=='one')
     #.options(joinedload(User.addresses))
     .first())

numpy array indicator operation

I want to modify an empty bitmap by given indicators (x and y axis).
For every coordinate given by the indicators the value should be raised by one.

So far so good everything seems to work. But if I have some similar indicators in my array of indicators it will only raise the value once.

>>> img
array([[0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0]])

>>> inds
array([[0, 0],
       [3, 4],
       [3, 4]])

Operation:

>>> img[inds[:,1], inds[:,0]] += 1

Result:

>>> img
    array([[1, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 1, 0]])

Expected result:

>>> img
    array([[1, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 0, 0],
           [0, 0, 0, 2, 0]])

Does someone have an idea how to solve this? Preferably a fast approach without the use of loops.

Solution:

This is one way. Counting algorithm courtesy of @AlexRiley.

For performance implications of relative sizes of img and inds, see @PaulPanzer’s answer.

# count occurrences of each row and return array
counts = (inds[:, None] == inds).all(axis=2).sum(axis=1)

# apply indices and counts
img[inds[:,1], inds[:,0]] += counts

print(img)

array([[1, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 0, 0],
       [0, 0, 0, 2, 0]])

Difference between get and dunder getitem

I am reading Fluent Python and trying to get a deeper understanding of dictionaries.

So when I run the below, the results are easy to understand in that both get() and dunder getitem() return the same result

sample = {'a':1, 'b':2}
print(sample.__getitem__('a')) # 1
print(sample.get('a')) # 1

When I subclass dict with get(), I get a working instance

class MyDict(dict):
    def __missing__(self, key):
        return 0

    def get(self, key):
        return self[key]

d = MyDict(sample)
print(d['a']) # 1
print(d['c']) # 0

Now if I replace get() with dunder getitem() I get an error and I am unsure why.

class MyDict2(dict):
    def __missing__(self, key):
        return 0

    def __getitem__(self, key):
        return self[key]

d = MyDict2(sample)
print(d['a'])
print(d['c'])

error

RecursionError: maximum recursion depth exceeded while calling a Python object

So the question is, what is the difference between get and dunder getitem in this situation and why does this cause a recursion error?

Solution:

That is because self[key] in MyDict2.__getitem__(key) is equivalent to (i.e., calls) self.__getitem__(key) => infinite recursion.

Generate all possible lists by replacing elements with 0

I would like to create from a list all the different list were 0,1,2,3…all element are replaced by an other
For example, if the replacement item is 0:

L=[1,2,3]
->[1,2,3],[0,2,3],[1,0,3],[1,2,0],[0,0,3],[0,2,0],[1,0,0],[0,0,0]

So far, I’ve tried I managed to do what I whant using Itertools but only in the case where 1 value is replaced by 0
Does anyone know how to do this ?

Solution:

This is one way using itertools. The benefit of this method is that it is lazy.

A new list is produced on every __next__ call of the generator transformer.

Alternatively, as below, you can output all combinations by calling list on the generator function.

from itertools import combinations, chain

A = [1, 2, 3]

def transformer(x):
    idx = chain.from_iterable(combinations(range(len(x)), i) for i in range(len(x)+1))
    for indices in idx:
        y = x.copy()
        for j in indices:
            y[j] = 0
        yield y

res = list(transformer(A))

print(res)

[[1, 2, 3], [0, 2, 3], [1, 0, 3], [1, 2, 0], [0, 0, 3], [0, 2, 0], [1, 0, 0], [0, 0, 0]]

Splitting a string from right at intervals in python

I’m trying to split a string from the right. Following is the code.

string = "abcde" 
n = len(string)
slices = [string[i-3:i] for i in range(n,0,-3)]
print (slices)

I get the output as ['cde', '']. I’m trying to get ['cde', 'ab']

But when I split it from left it gives the proper output, i.e..,

string = "abcde" 
slices = [string[i:i+3] for i in range(0,n,3)]
print (slices)

output: ['abc', 'de']

Can anyone point out where am I going wrong?

Solution:

You are close. You need to floor the first indexing argument at 0:

x = "abcde" 
n = len(x)
slices = [x[max(0,i-3):i] for i in range(n,0,-3)]

['cde', 'ab']

The reason your code does not work is because with positive indices, falling off the end means going as far as you can.

While negative indices means starting from the end, rather than going to the start and no further.

Running Python code in Vim without saving

Is there a way to run my current python code in vim without making any changes to the file? Normally, when I want to test my code from within vim, I would execute this:

:w !python

However, this overrides the current file I am editing. Often, I add print statements or comment stuff out to see why my code isn’t working. I do not want such changes to overwrite a previous version of whatever .py file I’m currently working on. Is there a way to do so? Perhaps a combination of saving to a temporary file and deleting it afterwards?

Solution:

You have already answered your own question:

:w !python

will run the file in python without saving it. Seriously, test it out yourself! make some changes, run :w !python and then after it runs, run :e!. It will revert all of your changes.

The reason this works is because :w does not mean save. It means write, and by default, it chooses to write the file to the currently selected file, which is equivalent to saving. In bash speak, it’s like

cat myfile > myfile

But if you give an argument, it will write the file to that stream rather than saving. In this case, your writing it to python, so the file is not saved.


I wrote a much longer answer on this topic here.