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())

passing parameters from groovy to python ( Jenkins job)

I am using groovy to call a python in my Jenkins job. i would like to pass few parameters also to the python and i need to use those in the python

I am calling the python like below

result = sh(returnStdout:true , script: '#!/bin/sh -e\n' + 'python test.py').trim()

The parameters i need to pass are jenkins build job parameters.

Can you suggest a solution to this problem.?

Solution:

Try:

cmd = """#!/bin/sh -e\n' + 'python test.py ${JENKINS_VAR_1} ${JENKINS_VAR_1}"""
result = sh(returnStdout:true , script: cmd).trim()

Assuming you already have the code in python to access the argument.

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.