generator expression with value check - python

I have the following snippet of code to find out whether any pair from a given list of numbers matches a given sum.
I have implemented the function as follows
def google(numbers, total):
complement =[]
for x in numbers:
if x in complement:
return True
else: complement.append(total-x)
return False
print google([1,2,3,4,5],8)
My question is, is there ANY POSSIBLE way of implementing this as a generator expression. ?
For example is there a way to check if the currently partially created generator has a given value inside comprehension ?

If you really want to do this, all things are possible, but not all things are desirable:
from itertools import combinations, dropwhile
def google(numbers, total):
return bool(next(dropwhile(lambda c: sum(c) != total, combinations(numbers, 2)), False))
We iterate through all the possible 2-number combinations of numbers using combinations and compare them to total.
Using dropwhile, we can emulate the short-circuit behaviour of your original code, getting only the first combination that satisfies the condition, if it exists. It will then, as a non-empty tuple, be converted to the boolean literal True. Otherwise, next will see that dropwhile is empty, and return the default value False.
Testing:
print(google([1, 2, 3, 4, 5], 8))
print(google([1, 2, 3, 4], 8))
Output:
True
False

Related

Is there another way besides "all" to check if all elements values before my target element are true?

I'm trying to return true if only all the previous elements are true up to the current position.
I have it set up with all function but I don't want to code it this way
def check(lightsOnOff, light):
for light in lights[:light]:
if not on:
return False
return True
count = count + 1
In general all is a useful construct to use, I can see why it looks wrong in this expression
all(list(lightsOnOff.values())[:light])
but the smelly part is actually the list(iterable)[:number] construction, which forces construction of the whole list then truncates it.
As an important aside, if lightsOnOff is a dict (not e.g. an OrderedDict) your code will be non-deterministic (see notes at bottom).
If you don't want to create a list and slice it, you can leverage itertools:
from itertools import islince
...
all(islice(lightsOnOff.values(), n))
As a frame challenge, if your dict has an order and you know the keys, you can simply rewrite it as:
all(lightsOnOff[k] for k in keys[:light])
and if your dict has keys that are ordered and e.g. integers, just use a list?
all(listOfLights[:light])
Provided you want to implement all yourself on an arbitrary list, you can do something like:
my_list = [1, 7, 2, 1, None, 2, 3]
up_to_ix = 5
def my_all(some_list, up_to_index):
for element in some_list[:up_to_index]:
if not element:
return False
return True
my_all(my_list, up_to_ix)
The function will loop through all elements in the list up to, but excluding the some_index and if it finds at least one Falsy value, will return False, otherwise True.

Lambda function error while using python3

I have a piece of code that works in Python 2.7 but not in Python3.7. Here I am trying to sort by values of a lambda function.
def get_nearest_available_slot(self):
"""Method to find nearest availability slot in parking
"""
available_slots = filter(lambda x: x.availability, self.slots.values())
if not available_slots:
return None
return sorted(available_slots, key=lambda x: x.slotNum)[0]
The error I get is:
File "/home/xyz/Desktop/parking-lot/parking-lot-1.4.2/parking_lot/bin/source/parking.py", line 45, in get_nearest_available_slot
return sorted(available_slots, key=lambda x: x.slotNum)[0]
IndexError: list index out of range
What am I doing wrong here?
The answer is simple: it's because of how filter works.
In Python 2, filter is eagerly evaluated, which means that once you call it, it returns a list:
filter(lambda x: x % 2 == 0, [1, 2, 3])
Output:
[2]
Conversely, in Python 3, filter is lazily evaluated; it produces an object you can iterate over once, or an iterator:
<filter at 0x110848f98>
In Python 2, the line if not available_slots stops execution if the result of filter is empty, since an empty list evaluates to False.
However, in Python 3, filter returns an iterator, which always evaluates to True, since you cannot tell if an iterator has been exhausted without trying to get the next element, and an iterator has no length. See this for more information.
Because of this, a case exists where an empty iterator gets passed to sorted, producing another empty list. You cannot access the element at position 0 of an empty list, so you get an IndexError.
To fix this, I suggest evaluating the condition strictly. You could do something like this, replacing sorted with min, since we only need one value:
def get_nearest_available_slot(self):
"""Method to find nearest availability slot in parking
"""
available_slots = [slot for slot in self.slots.values() if slot.availability]
if available_slots:
return min(available_slots, key=lambda x: x.slotNum)
else:
return None

Reversing ONLY integers in list without slice or reverse()

I am trying to create a program to reverse only the integers in a given list, ignoring floats and strings. In addition, It cannot use any built in functions to do so (reverse() and [::-1]). So far, I have
def intvert(lst):
finallst = []
for i in range(len(lst)-1,-1,-1):
if i == type(int):
finallst.append(i)
elif i != type(int):
continue
return finallst
However, this only produces [] as the output
example: (1,g,2.6,2,3,4,h,dfgs,dsgfgdsg,5) becomes (5,4,3,2,1)
A generator is useful for these kinds of tasks. Note it is better to use isinstance versus type. Also you do not have to explicitly check for non-int types if you aren't going to do anything with them.
def intvert(lst):
for i in range(len(lst)-1, -1, -1):
if isinstance(lst[i], int):
yield lst[i]
list(intvert([1, 2, 3, 4]))
# [4, 3, 2, 1]
list(intvert([1, 'test', 2, ['another test'], 3, 4]))
# [4, 3, 2, 1]
Note that the generator function can be optimised further by converting it into a generator expression:
def intvert(lst):
return (lst[i] for i in range(len(lst)-1, -1, -1) if isinstance(lst[i], int))
The reason nothing's getting appended to your list is because your if condition is erroneous. By typing if i == type(int) you're trying to verify if your counter variable "i" (always an integer) is equal to the type of Python's reserved keyword "int"... which doesn't really make sense.
Here's an if condition that should get this working:
if isinstance(lst[i],int):
finallst.append(lst[i])
You need to index into a value in your list (some indexing exercises here). The "isinstance()" method checks the type of the value at the ith position in "lst" to type int. If True, the value is appended to your list.
Fyi: You also don't need the elif or an else block in this case.
def is_int(val):
if type(val) == int:
return True
else:
return False
lis=[1,"aa",2,"b",3,"c"]
lim=[]
for x in lis:
if is_int(x)==True:
lim.append(x)
k=len(lim)
for i in range(k//2):
a=lim[i]
lim[i]=lim[k-1]
lim[k-1]=a
print(lim)
'''this code does so same logic as yours tell me if you didnt understand.i used
type operater you can use something else.'''
To filter your list you can use list comprehensions:
input_list = [1,2.6,'hi',3,'blah',{},99]
filtered_list = [x for x in input_list if type(x) is int]
>>> [1,3,99]
Then you can reverse that list in whatever way you want according to your homework constraints. Normally you'd call .reverse() on the filtered_list but up to you. If list.reverse() is out, I don't know if list.instert() is allowed, but if it is, then you can do:
reversed_filtered_list = []
for i in filtered_list:
reversed_filtered_list.insert(0, i)

Python. How to optimize search functions

There any way to optimize these two functions ?
first function:
def searchList(list_, element):
for i in range (0,len(list_)):
if(list_[i] == element):
return True
return False
second function:
return_list=[]
for x in list_search:
if searchList(list_users,x)==False:
return_list.append(x)
Yes:
return_list = [x for x in list_search if x not in list_users]
The first function basically checks for membership, in which case you could use the in keyword. The second function can be reduced to a list comprehension to filter out elements from list_search list based on your condition.
For first function
def searchList(list, element):
return element in list
You can make it in 1 line
searchList = lambda x,y: y in x
For 2nd, use a list comp like shown in the other answer
What you are doing with your two functions is building the complement as ozgur pointed out.
Using sets is the most easy thing here
>>> set([2,2,2,3,3,4])- set([1,2,2,4,5])
set([3])
your list_search would be the first list and your list_users the second list.
The only difference is that your new user is only once in the result no matter how often it is in the list_search
Disclaimer: I assumed list_search has no duplicate elements. Otherwise, use this solution.
What you want is exactly the set complement of list_users in list_search.
As an alternative approach, you can use sets to get the difference between two lists and I think it should be much more performant than the naive look up which takes 0(n^2).
>>> list_search = [1, 2, 3, 4]
>>> list_users = [4, 5, 1, 6]
>>> print set(list_search).difference(list_users)
>>> {2, 3}

How to uniformly handle A LIST or A LIST OF LIST (multi-dimensional list)

Without any heavy libraries such as numpy, I want to uniformly handle a single list or multi-dimensional list in my code. For example, the function sum_up(list_or_matrix) should
return 6 for argument [1, 2, 3] and return 9 for [[1, 2, 3], [1, 2, 0]].
My question is:
1. Can I code in a way without explicitly detecting the dimension of my input such as by isinstance(arg[0], (tuple, list))?
2. If I have to do so, is there any elegant way of detecting the dimension of a list (of list of list ...), e.g. recursively?
As many users suggested you can always use dict instead of list for any-dimensinal collection. Dictionaries are accepting tuples as arguments as they are hashable. So you can easy fill-up your collection like
>>> m = {}
>>> m[1] = 1
>>> m[1,2] = 12
>>> m[1,2,"three",4.5] = 12345
>>> sum(m.values()) #better use m.itervalues() in python 2.*
12358
You can solve this problem using recursion, like this:
#!/usr/bin/env python
def sum(seq_or_elem):
if hasattr(seq_or_elem, '__iter__'):
# We were passed a sequence so iterate over it, summing the elements.
total = 0
for i in seq_or_elem:
total += sum(i)
return total
else:
# We were passed an atomic element, the sum is identical to the passed value.
return seq_or_elem
Test:
>>> print(sum([1, 2, [3, [4]], [], 5]))
15
Well I dont see a way if you are planning to use a single function to sum up your list like sum_up(list_or_matrix).
If you are having a list of lists I would only imagine you need to loop through the list to find out if its a 1-D or a 2-D list. Anyway whats wrong in looping?
def sum_up(matrix):
2DMatrix = False
for item in matrix:
if type(item) == list:
2DMatrix = True
if(2DMatrix):
//sum 2d matrix
else:
//sum 1d matrix
A simple way to sum up a matrix is as follow:
def sum_up(matrix):
if isinstance(matrix, (tuple, list)):
return sum(matrix)
else:
return sum((sum(x) for x in matrix))
The 'else' branch uses list comprehension, a powerful and quick tool.
You could sum recursively until you have a scalar value:
def flatten(x):
if isinstance(x, list):
return sum(map(flatten, x))
return x
Note: you can use collections.Iterable (or another base class) instead of list, depending on what you want to flatten.

Categories