Here is my code:
x = [(1, 2, 3), (4, 5, 6)]
for tup in x:
if len(tup) == 3:
print(True)
else:
print(False)
I want to validate tuples in a list have the same length of 3. If any of the tuples in the list has more or less than 3 values, I want to print single output False. If all the tuples have 3 values then it should print single output True.
Currently, the for loop produces more than 1 output. How do I tweak the for loop?
You can use all():
if all(len(tup) == 3 for tup in x):
print(True)
else:
print(False)
Here is a one-liner:
print(all(len(t) == 3 for t in x))
A convenient solution for this problem is to use the break keyword and loop manipulation like so:
x = [(1, 2, 3), (4, 5, 6)]
tupleCheck = True
for tup in x:
if len(tup) != 3:
tupleCheck = False # Here, the program realizes that a tuple does not have a length of 3...
break # and aborts.
print(tupleCheck)
Although somewhat redundant, this solution is quite readable.
Another approach would be to use namedTuple. Instead of checking the list of point you could create your list of point using this. doc.
>>> Point = namedtuple('Point', ['x', 'y'])
>>> p = Point(11, y=22) # instantiate with positional or keyword arguments
This gives a list corresponding to each tuple:
x=[(1,2,3),(1,2,2)]
d=[len(a)==3 for a in x]
p=True
for i in d:
p= i and p
print p
Related
I am trying to write an if statement in Python 3:
if n % 2 == 0:
list.append(2)
elif n % 3 == 0:
list.append(3)
elif n % 5 == 0:
list.append(5)
Is there a more space conservative way of doing this?
I thought about using lambda expressions, but these bits of code don't seem to work.
if (lambda i: n % i == 0)(i in [2,3,5])
list.append(i)
and
if (lambda i: n % i == 0)([2,3,5])
list.append(i)
Is there a way to do this using lambda expressions? Or do I need a different approach? Also, if I use lambda expressions, will I be able to use the value of i for which the condition matches (like appending it to a list)?
>>> n = 33
>>> [i for i in (2, 3, 5) if n % i == 0]
[3]
>>> n = 10
>>> [i for i in (2, 3, 5) if n % i == 0]
[2, 5]
To get the same result as if/elif/elif statements in the question:
your_list += next(([d] for d in [2, 3, 5] if n % d == 0), [])
Note: only the first divisor is appended to the list. See find first element in a sequence that matches a predicate.
I can't do it with lambda functions but I think this approach with help u
list = [1,2,3]
n = 9
[list.append(i) for i in (2,3,5) if n % i == 0]
print list
[1, 2, 3, 3]
and so on ..
Like J.F. Sebastian`s answer this gives only the first divisor:
res_list.extend([i for i in (2, 3, 5) if n % i == 0][:1])
The [:1] takes only the first element of the list and
gives an empty list if the list is empty (because a slice of an empty
list is always an empty list).
Now, extend() adds a one-element list as a single element to
your result list or nothing for a zero-element list.
Say I have list of tuples:
list = [(1,5), (1,7), (2,3)]
Is there a way in Python to write something like
if (1, *) in list: do things
where * means "I don’t care about this value"? So we are checking if there is a tuple with 1 at the first position and with whatever value on the second one.
As far as I know there are special mechanisms in other languages, but I just don’t know the name of this particular problem. So is there similar behavior in Python?
P.S.: I know that I can use list comprehensions here. I am just interested in this particular mechanism.
You can use the any() function:
if any(t[0] == 1 for t in yourlist):
This efficiently tests and exits early if 1 is found in the first position of a tuple.
A placeholder object like you're asking for isn't supported natively, but you can make something like that yourself:
class Any(object):
def __eq__(self, other):
return True
ANYTHING = Any()
lst = [(1,5), (1,7), (2,3)]
The __eq__ method defines how two objects test for equality. (See https://docs.python.org/3/reference/datamodel.html for details.) Here, ANYTHING will always test positive for equality with any object. (Unless that object also overrode __eq__ in a way to return False.)
The in operator merely calls __eq__ for each element in your list. I.e. a in b does something like:
for elem in b:
if elem == a:
return True
This means that, if you say (1, ANYTHING) in lst, Python will first compare (1, ANYTHING) to the first element in lst. (Tuples, in turn, define __eq__ to return True if all its elements' __eq__ return True. I.e. (x, y) == (a, b) is equivalent to x==a and y==b, or x.__eq__(a) and y.__eq__(b).)
Hence, (1, ANYTHING) in lst will return True, while (3, ANYTHING) in lst will return False.
Also, note that I renamed your list lst instead of list to prevent name clashes with the Python built-in list.
Not all of my solution methods provided below will be necessarily efficient. My goal is to demonstrate every possible solution method I can think of - at the end of my answer I provide "benchmark" results to show why or why not you should use one certain method over another. I believe that is a good way of learning, and I will shamelessly encourage such learning in my answers.
Subset + hash sets
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> set([l[0] for l in a_list])
{1, 2}
>>>
>>> 1 in set([l[0] for l in a_list])
True
map(), and anonymous functions
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> map(lambda x: x[0] == 1, a_list)
[True, True, False]
>>>
>>> True in set(map(lambda x: x[0] == 1, a_list))
True
filter and anonymous functions
>>> a_list = [(1,5), (1,7), (2,3)]
>>>
>>> filter(lambda x: x[0] == 1, a_list)
[(1,5), (1,7)]
>>>
>>> len(filter(lambda x: x[0] == 1, a_list)) > 0 # non-empty list
True
MICROBENCHMARKS
Conditions
1000 items
100K repetition
0-100 random range
Python 2.7.10, IPython 2.3.0
Script
from pprint import pprint
from random import randint
from timeit import timeit
N_ITEMS = 1000
N_SIM = 1 * (10 ** 5) # 100K = 100000
a_list = [(randint(0, 100), randint(0, 100)) for _ in range(N_ITEMS)]
set_membership_list_comprehension_time = timeit(
"1 in set([l[0] for l in a_list])",
number = N_SIM,
setup="from __main__ import a_list"
)
bool_membership_map_time = timeit(
"True in set(map(lambda x: x[0] == 1, a_list))",
number = N_SIM,
setup="from __main__ import a_list"
)
nonzero_length_filter_time = timeit(
"len(filter(lambda x: x[0] == 1, a_list)) > 0",
number = N_SIM,
setup="from __main__ import a_list"
)
any_list_comprehension_time = timeit(
"any(t[0] == 1 for t in a_list)",
number = N_SIM,
setup="from __main__ import a_list"
)
results = {
"any(t[0] == 1 for t in a_list)": any_list_comprehension_time,
"len(filter(lambda x: x[0] == 1, a_list)) > 0": nonzero_length_filter_time,
"True in set(map(lambda x: x[0] == 1, a_list))": bool_membership_map_time,
"1 in set([l[0] for l in a_list])": set_membership_list_comprehension_time
}
pprint(
sorted(results.items(), key = lambda x: x[1])
)
Results (in seconds)
[('any(t[0] == 1 for t in a_list)', 2.6685791015625), # winner - Martijn
('1 in set([l[0] for l in a_list])', 4.85234808921814),
('len(filter(lambda x: x[0] == 1, a_list)) > 0', 7.11224889755249),
('True in set(map(lambda x: x[0] == 1, a_list))', 10.343087911605835)]
Who's got the last laugh now? ... Martijn (at least I tried)
MORAL OF THE STORY: Don't spend more than 10 minutes "proving" your inferior solution is faster and more efficient on a small test data, when another user's answer is the de-facto correct one
This can be done in Python using list comprehension.
ex:
a= [(1, 2), (3, 4), (4, 5), (1, 4)]
[i for i in a if i[0] == 1]
Will give you:
[(1, 2), (1, 4)]
Indexing is the simplest but if you wanted to use syntax similar to your example where you wanted to assign the first value to a variable and ignore the rest you could use python3's extended iterable unpacking.
In [3]: [a for a,*_ in l]
Out[3]: [1, 1, 2]
Or with the any logic:
In [4]: l = [(1,5), (1,7), (2,3)]
In [5]: any(a == 1 for a,*_ in l)
Out[5]: True
Or mimicking any without the function call:
In [23]: l = [(1,5), (1,7), (2,3)]
In [24]: g = (a for a,*_ in l)
In [25]: 1 in g
Out[25]: True
In [26]: list(g)
Out[26]: [1, 2]
number of element in tuple could be handled also.
>>> import operator
>>> mylist = [(1,2), (1,5), (4,5,8)]
>>> any(i==1 for i in map(operator.itemgetter(0), mylist))
True
It sounds like you actually want filter(), not any():
tuple_list = [(1,5), (1,7), (2,3)]
for pair in filter(lambda pair: (pair[0] == 1), tuple_list):
print "Second value {pair[1]} found from {pair}".format(pair=pair)
...
Second value 5 found from (1, 5)
Second value 7 found from (1, 7)
The filter() method is great because you can provide a function directly to it. This lets you specify a certain key to filter on, etc. To simplify it further, use a lambda expression to make the entire thing into a one-liner.
Using map can do operations of current element in list:
l = [1,2,3,4,5,6];
print(list(map(lambda x: x*2, l)))
# gives [2, 4, 6, 8, 10, 12]
In above, multiply by 2 is done for all elements in l. But how to mulitiply by 2 an element in l, only if previous value in l is odd? Can use map for this?
For example to get:
[1,4,3,8,5,12] % only 2, 4 and 6 from l are multiplyied by 2, because before them there are odd numbers 1,3,5.
You can use map if you do it on an enumerated version:
print(list(map(lambda index,x: x*2 if index > 1 and l[index-1] & 1 else x, enumerate(l))))
However, as you might have noticed, that's really not very readable. It's better to just use a list comprehension or a for loop:
print([x*2 if index > 1 and l[index-1] & 1 else x
for index, x in enumerate(l)])
You can use zip in combination with map:
print(l[:1] + list(map(lambda x: x[1]*2 if x[0] & 1 else x[1], zip(l, l[1:]))))
Note that I had to explicitly prepend the first element of the list because it has no previous element to test.
You can zip the list along with a sliced copy of the list to pair all of the items:
>>> l = [1, 2, 3, 4, 5, 6]
>>> zip(l, l[1:])
[(1, 2), (2, 3), (3, 4), (4, 5), (5, 6)]
You can use something callable to track your previous value. Depending on how abstract you want this:
prev = [0]
def callback(x):
val = ((prev[0] % 2) + 1) * x
prev[0] = x
return val
print list(map(callback, l))
I realise that it was probably just a trivial example, but thought it worth mentioning that in your example case the condition "if the previous value is odd" is the same as "if the current value is even" (at least for your sample input). In which case I would just use
print([x if x&1 else x*2 for x in l])
For the more general case and assuming the condition may be more complex than just "previous item is odd", I would take a few lines to express the solution clearly. Python's generators are a good fit:
>>> def double_if_prev_odd(l):
... prev_odd = False # initial condition for 1st element
... for x in l:
... yield x**2 if prev_odd else x
... prev_odd = x&1
...
>>> list(double_if_prev_odd(l))
[1, 4, 3, 16, 5, 36]
Is it possible in Python to run multiple counters in a single for loop as in C/C++?
I would want something like -- for i,j in x,range(0,len(x)): I know Python interprets this differently and why, but how would I run two loop counters concurrently in a single for loop?
You want zip in general, which combines two iterators, as #S.Mark says. But in this case enumerate does exactly what you need, which means you don't have to use range directly:
for j, i in enumerate(x):
Note that this gives the index of x first, so I've reversed j, i.
You might want to use zip
for i,j in zip(x,range(0,len(x))):
Example,
>>> x = [1, 2, 3]
>>> y = [4, 5, 6]
>>> zipped = zip(x, y)
>>> print zipped
[(1, 4), (2, 5), (3, 6)]
>>> for a,b in zipped:
... print a,b
...
1 4
2 5
3 6
>>>
Note: The correct answer for this question is enumerate as other mentioned, zip is general option to have multiple items in a single loop
for i,j in enumerate(x)
I have a list of tuples (each tuple item is a pair of integers) and I would like to add a constant value to each tuple in the list.
For example
[(x0,y0),(x1,y1),...] -> [(x0+xk,y0+yk),(x1+xk,y1+yk)....]
xk,yk are constants
How do I do this
Thanks
Use numpy, e.g.,
>>> import numpy as np
>>> a = np.array([[1,2],[2,3]])
>>> print a
[[1 2]
[2 3]]
>>> print a + 2
[[3 4]
[4 5]]
>>>> l = [(1,2), (3,4)]
>>>> for i, e in enumerate(l):
.... l[i] = (e[0]+xk, e[1]+yk)
As always, untested. ;-)
If you don't need to do it in place, it's even simpler
>>>> l = [(e[0]+xk, e[1]+yk) for e in l]
You can't add a constant to a tuple because tuples are immutable.
You can however create a new tuple from the old one by incrementing it's values. See jae's answer for the basics of how to do this.
You should note however that you will be creating a lot of new tuples in this loop and this may not be a very efficient way of handling this. You should investigate numpy (as suggested by nikow) or perhaps using lists or coordinate objects instead of tuples.
an example to add things to tuple
>>> a=(1,2)
>>> a+=(1,)
>>> a
(1, 2, 1)
you can adapt it to your requirement
Solution:
l = [(i[0]+k[0], i[1]+k[1]) for i in l]
Test code:
l = [(1,2), (3,4)]
k = (10, 100)
l = [(i[0]+k[0], i[1]+k[1]) for i in l]
assert l == [(11, 102), (13, 104)]