python operations with sets - python

I use python only occasionally, sorry for a seemingly trivial question
>>> a = set(((1,1),(1,6),(6,1),(6,6)))
>>> a
set([(6, 1), (1, 6), (1, 1), (6, 6)])
>>> a - set(((1,1)))
set([(6, 1), (1, 6), (1, 1), (6, 6)])
>>> a.remove((1,1))
>>> a
set([(6, 1), (1, 6), (6, 6)])
why '-' operator didn't delete the element but the remove did ?

Because you missed a comma:
>>> set(((1,1)))
set([1])
should be:
>>> set(((1,1),))
set([(1, 1)])
or, to be more readable:
set([(1,1)])
or even (Py2.7+):
{(1,1)}

You missed a comma when trying to specify a tuple of one element. Syntax for tuples is indeed somewhat tricky...
A tuple is built using commas, not parenthesis
sometimes it is mandatory to add parenthesis around it
an empty tuple is however represented by an empty pair of parenthesis
not always a pair of parenthesis wrapping zero or more expression separated by commas is a tuple
Some examples
w = 1, 2, 3 # creates a tuple, no parenthesis needed
w2 = (1, 2, 3) # works too, like x+y is the same as (x+y)
x, y, z = w # unpacks a tuple
k0 = () # creates an empty tuple
k1 = (1,) # a tuple with one element (note the comma)
k = (1) # just a number, NOT a tuple
foo(1, 2, 3) # call passing three numbers, not a tuple
bar((1, 2, 3)) # call passing a tuple
if x in 1, 2: # syntax error, parenthesis are needed
pass
for x in 1, 2: # ok here
pass
gen = (x for x in 1, 2) # error, parenthesis needed here around (1, 2)

Related

Python Assign Multiple Variables with Map Function

With Python, I can assign multiple variables like so:
a, b = (1, 2)
print(a)
print(b)
# 1
# 2
Can I do something similar with the map function?
def myfunc(a):
return (a+1, a-1)
a_plus_one, a_minus_one = map(myfunc, (1, 2, 3))
# or
a_plus_one, a_minus_one = list(map(myfunc, (1,2,3)))
print(a_plus_one)
print(a_minus_one)
These attempts give me too many values to unpack error.
Edit:
Desired output is two new lists.
a_plus_one = (2, 3, 4)
a_minus_one = (0, 1, 2)
It looks like you're misunderstanding how map works. Look at list(map(myfunc, (1,2,3))):
[(2, 0), (3, 1), (4, 2)]
You want to transpose that using zip:
>>> a_plus_one, a_minus_one = zip(*map(myfunc, (1,2,3)))
>>> a_plus_one
(2, 3, 4)
>>> a_minus_one
(0, 1, 2)
For more info: Transpose list of lists

Is There A Universal Selector Option For if...in Clauses?

I have a "large" list of tuples:
thelist=[(1,2),(1,3),(2,3)]
I want to check whether any tuple in the list starts with a 1, and if it does, print "aaa":
for i in thelist:
templist.append((i[0],i))
for i in templist:
if i[0]==1:
print("aaa")
break
Which is rather ardurous as I have to create the templist. Is there any way I can do this:
if (1,_) in thelist:
print("aaa")
Where _ is the universal selector. Note that the list would be very large and thus it is very costly to implement another list.
There isn't, although you can just use any
any(i[0] == 1 for i in thelist) --> Returns true if the first element is 1
If you don’t actually need the actual tuple, like you do in your example, then you can actually use tuple unpacking for exactly that purpose:
>>> the_list = [(1, 2), (1, 3), (2, 3)]
>>> for x, y in the_list:
if x == 1:
print('aaa')
break
aaa
If you add a * in front of the y, you can also unpack tuples of different sizes, collecting the remainder of the tuple:
>>> other_list = [(1, 2, 3, 4, 5), (1, 3), (2, 3)]
>>> for x, *y in other_list:
if x == 1:
print(y)
break
[2, 3, 4, 5]
Otherwise, if you just want to filter your list based on some premise and then do something on those filtered items, you can use filter with a custom function:
>>> def startsWithOne(x):
return x[0] == 1
>>> thelist = [(1, 2), (1, 3), (2, 3)]
>>> for x in filter(starts_with_one, the_list):
print(x)
(1, 2)
(1, 3)
This is probably the most flexible way which also avoids creating a separate list in memory, as the elements are filtered lazily when you interate the list with your loop.
Finally, if you just want to figure out if any of your items starts with a 1, like you do in your example code, then you could just do it like this:
>>> if any(filter(starts_with_one, the_list)):
print('aaa')
aaa
But I assume that this was just an oversimplified example.

Eliminating tuples from list of tuples based on a given criterion

So the problem is essentially this: I have a list of tuples made up of n ints that have to be eliminated if they dont fit certain criteria. This criterion boils down to that each element of the tuple must be equal to or less than the corresponding int of another list (lets call this list f) in the exact position.
So, an example:
Assuming I have a list of tuples called wk, made up of tuples of ints of length 3, and a list f composed of 3 ints. Like so:
wk = [(1,3,8),(8,9,1),(1,1,1)]
f = [2,5,8]
=== After applying the function ===
wk_result = [(1,3,8),(1,1,1)]
The rationale would be that when looking at the first tuple of wk ((1,3,8)), the first element of it is smaller than the first element of f. The second element of wk also complies with the rule, and the same applies for the third. This does not apply for the second tuple tho given that the first and second element (8 and 9) are bigger than the first and second elements of f (2 and 5).
Here's the code I have:
for i,z in enumerate(wk):
for j,k in enumerate(z):
if k <= f[j]:
pass
else:
del wk[i]
When I run this it is not eliminating the tuples from wk. What could I be doing wrong?
EDIT
One of the answers provided by user #James actually made it a whole lot simpler to do what I need to do:
[t for t in wk if t<=tuple(f)]
#returns:
[(1, 3, 8), (1, 1, 1)]
The thing is in my particular case it is not getting the job done, so I assume it might have to do with the previous steps of the process which I will post below:
max_i = max(f)
siz = len(f)
flist = [i for i in range(1,max_i +1)]
def cartesian_power(seq, p):
if p == 0:
return [()]
else:
result = []
for x1 in seq:
for x2 in cartesian_power(seq, p - 1):
result.append((x1,) + x2)
return result
wk = cartesian_power(flist, siz)
wk = [i for i in wk if i <= tuple(f) and max(i) == max_i]
What is happening is the following: I cannot use the itertools library to do permutations, that is why I am using a function that gets the job done. Once I produce a list of tuples (wk) with all possible permutations, I filter this list using two parameters: the one that brought me here originally and another one not relevant for the discussion.
Ill show an example of the results with numbers, given f = [2,5,8]:
[(1, 1, 8), (1, 2, 8), (1, 3, 8), (1, 4, 8), (1, 5, 8), (1, 6, 8), (1, 7, 8), (1, 8, 1), (1, 8, 2), (1, 8, 3), (1, 8, 4), (1, 8, 5), (1, 8, 6), (1, 8, 7), (1, 8, 8), (2, 1, 8), (2, 2, 8), (2, 3, 8), (2, 4, 8), (2, 5, 8)]
As you can see, there are instances where the ints in the tuple are bigger than the corresponding position in the f list, like (1,6,8) where the second position of the tuple (6) is bigger than the number in the second position of f (5).
You can use list comprehension with a (short-circuiting) predicate over each tuple zipped with the list f.
wk = [(1, 3, 8), (8, 9, 1), (1, 1, 1), (1, 9, 1)]
f = [2, 5, 8] # In this contrived example, f could preferably be a 3-tuple as well.
filtered = [t for t in wk if all(a <= b for (a, b) in zip(t, f))]
print(filtered) # [(1, 3, 8), (1, 1, 1)]
Here, all() has been used to specify a predicate that all tuple members must be less or equal to the corresponding element in the list f; all() will short-circuit its testing of a tuple as soon as one of its members does not pass the tuple member/list member <= sub-predicate.
Note that I added a (1, 9, 1) tuple for an example where the first tuple element passes the sub-predicate (<= corresponding element in f) whereas the 2nd tuple element does not (9 > 5).
You can do this with a list comprehension. It iterates over the list of tuples and checks that all of the elements of the tuple are less than or equal to the corresponding elements in f. You can compare tuples directly for element-wise inequality
[t for t in wk if all(x<=y for x,y in zip(t,f)]
# returns:
[(1, 3, 8), (1, 1, 1)]
Here is without loop solution which will compare each element in tuple :
wk_1 = [(1,3,8),(8,9,1),(1,1,1)]
f = [2,5,8]
final_input=[]
def comparison(wk, target):
if not wk:
return 0
else:
data=wk[0]
if data[0]<=target[0] and data[1]<=target[1] and data[2]<=target[2]:
final_input.append(data)
comparison(wk[1:],target)
comparison(wk_1,f)
print(final_input)
output:
[(1, 3, 8), (1, 1, 1)]
P.S : since i don't know you want less and equal or only less condition so modify it according to your need.

Trying to understand the double index in python

def countSmaller(self, nums):
def sort(enum):
half = len(enum) / 2
if half:
left, right = sort(enum[:half]), sort(enum[half:])
for i in range(len(enum))[::-1]:
if not right or left and left[-1][1] > right[-1][1]:
smaller[left[-1][0]] += len(right)
enum[i] = left.pop()
else:
enum[i] = right.pop()
return enum
smaller = [0] * len(nums)
sort(list(enumerate(nums)))
return smaller
I am a new python coder so this query!.. In left[-1][1] , I understood [-1] makes me think the last index but what does the second index [1] mean.
The second index does the same as the first but with the nested value.
For exemple:
a = [(1, 2), (2, 3), (3, 4)]
a[-1] # (3, 4)
a[-1][1] # 4
In your example you don't have a list with numbers but enumerate objects converted to lists
sort(list(enumerate(nums)))
It means that you have data like this:
nums = [1, 2, 3, 4, 5]
enum_list = list(enumerate(nums)) # [(0, 1), (1, 2), (2, 3), (3, 4), (4, 5)]
It seems like left is an array containing tuples. I.e. Each element of the array is a tuple.
Ex: left=[(value1oftuple1,value2oftuple1),(value1ofarray2,value2ofarray2)]
In this case left[-1][1] would reference the first value in the last element of the array (value1ofarray2).
I found this by running your code and printing the value of left just before your code calls left[-1][1]. This way you can see what data type left is.

Python generating all nondecreasing sequences

I am having trouble finding a way to do this in a Pythonic way. I assume I can use itertools somehow because I've done something similar before but can't remember what I did.
I am trying to generate all non-decreasing lists of length L where each element can take on a value between 1 and N. For example if L=3 and N=3 then [1,1,1],[1,1,2],[1,1,3],[1,2,2],[1,2,3], etc.
You can do this using itertools.combinations_with_replacement:
>>> L, N = 3,3
>>> cc = combinations_with_replacement(range(1, N+1), L)
>>> for c in cc: print(c)
(1, 1, 1)
(1, 1, 2)
(1, 1, 3)
(1, 2, 2)
(1, 2, 3)
(1, 3, 3)
(2, 2, 2)
(2, 2, 3)
(2, 3, 3)
(3, 3, 3)
This works because c_w_r preserves the order of the input, and since we're passing a nondecreasing sequence in, we only get nondecreasing tuples out.
(It's easy to convert to lists if you really need those as opposed to tuples.)

Categories