Python: How to check if two lists are not empty - python

In Python, I know the pythonic way to check if a list is empty is
if not a:
# do things with empty list
To check if a list is not empty then, we would do:
if a:
# do things with my list
How would we check, simultaneously (as read), if two lists then are not empty?
if a and b:
# do things with my two lists
The above does not seem to work, and I'm unsure what (a and b) actually means. For a = [2], b = [1,3], (a and b) = [1,3]. What is the and operator actually doing here? If I end up reducing b = [] at some point, (a and b) = [] even though a is not empty.
Edit: My use case goes something like
while (a and b are not empty):
modify a
modify b
I would have naively thought that since if a checks if a list is not empty, if a and b would check if neither were empty, which is not the case.

It's working fine. For a = [2] and b = [1, 3], a and b is returning [1, 3] which is truthy, exactly as you would expect, because True and True is True. When you change b to [] it returns [], which is falsy, again exactly as you would expect, because True and False is False. So if a and b does exactly what you want.
What is actually happening is that and is returning the value that decided the truth of the expression. and doesn't always evaluate both sub-expressions; when the first is falsy, the whole expression is falsy and the second doesn't need to be evaluated, and therefore isn't. This is called short-circuiting. or behaves similarly (skipping evaluating the second part if the first part is truthy). Wherever and or or is able to make its decision, it returns that value.
Another way of looking at it: bool(a) and bool(a) == bool(a and b) in Python.

a and b is correct.
and returns the second argument if the first is true.

You can do this
if len(a) and len(b):
#do something

I think what you want is
>>> a, b = list(), list()
>>> while not (a and b):
... a.append(1)
... b.append(2)
...
>>> a, b
([1], [2])
>>>

and operator is compare two boolean values
bool([]) == False
so [] and b always return []; no matter what b is.

To build on kindall's answer - you could also concatenate the lists before doing the truthiness test:
a = []
b = []
c = [1]
bool(a + b) # False
bool(a + b + c) # True
Of course this would come with a performance penalty if you were doing something where that mattered.

Related

Why can't a list be constructed and modified in the same line?

For example, why is a not equal to b?
a = [1]
a.append(2)
print(a) # [1, 2]
b = [1].append(2)
print(b) # None
The syntax for b doesn't look wrong to me, but it is. I want to write one-liners to define a list (e.g. using a generator expression) and then append elements, but all I get is None.
It's because:
append, extend, sort and more list function are all "in-place".
What does "in-place" mean? it means it modifies the original variable directly, some things you would need:
l = sorted(l)
To modify the list, but append already does that, so:
l.append(3)
Will modify l already, don't need:
l = l.append(3)
If you do:
l = [1].append(2)
Yes it will modify the list of [1], but it would be lost in memory somewhere inaccessible, whereas l will become None as we discovered above.
To make it not "in-place", without using append either do:
l = l + [2]
Or:
l = [*l, 2]
The one-liner for b does these steps:
Defines a list [1]
Appends 2 to the list in-place
Append has no return, so b = None
The same is true for all list methods that alter the list in-place without a return. These are all None:
c = [1].extend([2])
d = [2, 1].sort()
e = [1].insert(1, 2)
...
If you wanted a one-liner that is similar to your define and extend, you could do
c2 = [1, *[2]]
which you could use to combine two generator expressions.
All built-in methods under class 'List' in Python are just modifying the list 'in situ'. They only change the original list and return nothing.
The advantage is, you don't need to pass the object to the original variable every time you modify it. Meanwhile, you can't accumulatively call its methods in one line of code such as what is used in Javascript. Because Javascript always turns its objects into DOM, but Python not.

Why does "[] is [ ]" evaluate to False in python

Try this in an interactive python shell.
[] is [ ]
The above returns False, why?
You created two mutable objects, then used is to see if those are the same object. That should definitely return False, or something would be broken.
You wouldn't ever want is to return true here. Imagine if you did this:
foo = []
bar = []
foo.append(42)
then you'd be very surprised if bar now contains 42. If is returned true, meaning that both [] invocations returned the exact same object, then appending to foo would be visible in the reference to bar.
For immutable objects, it makes sense to cache objects, at which point is may return true, like with empty tuples:
>>> () is () # are these two things the same object?
True
The CPython implementation has optimised empty tuple creation; you'll always get the exact same object, because that saves memory and makes certain operations faster. Because tuples are immutable, this is entirely safe.
If you expected to test for value equality instead, then you got the wrong operator. Use the == operator instead:
>>> [] == [] # do these two objects have the same value?
True
In python is does a reference equality check like [] and [] they are different objects you can check that by
print id([]),id([])
or
In [1]: id([])
Out[1]: 140464629086976
In [2]: id([])
Out[2]: 140464628521656
both will return different address and both are different object so is will always give false
[] is []
output
false
[] is like list(), if you do this:
a = list()
b = list()
clearly a and b are two completly different objects, hence:
a is b # False
like
list() is list() # False
like
[] is [] # False
The == operator compares the values of both the operands and checks for value equality. Whereas is operator checks whether both the operands refer to the same object or not.
id('') : 139634828889200
id('') : 139634828889200
id('') : 139634828889200
id([]) : 139634689473416
id([]) : 139634689054536
id([]) : 139634742570824

Strange behaviour when changing value of list in a list

While coding on a python project I noticed a strange behavior when I tried to change the value of a list in another list.
Not working code:
lst = []
to_add = [None,None,None]
for i in range(3):
lst.append(to_add)
for i in range(3):
lst[i][0] = anotherslistoflists[i][0]
To my surprise this example gave unexpected results. To be specific, every lst[i][0] got assigned with the same value which was the first element from the last index of the "anotherlistoflists" list.
Result example (when printing lst)
("word1",None,None)
("word1",None,None)
("word1",None,None)
Working code:
lst = []
for i in range(5):
lst.append([None,None,None])
# same code as above
Result example2 (expected result)
("word1",None,None)
("word2",None,None)
("word3",None,None)
Of course, as you can see the problem is solved but I was wondering why the first code does not work. Something is probably wrong with the "to_add" list but I don't understand what is the problem here.
You are appending the same list, to_add, three times. Then, once you modify it, all three items which point to it will reflect the same change. If you want to create a new copy with the same values, you could use the built-in list function:
for i in range(3):
lst.append(list(to_add))
You are adding the same list, to_add to lst:
>>> a = [None]
>>> b = [a]
>>> c = [a]
>>> print a, b, c
[None] [[None]] [[None]]
>>> a[0] = 1
>>> print a, b, c
[1] [[1]] [[1]]
In the first case you are not adding a copy of add_to_list you are actually adding that exact list over and over, so when you change it later you're changing the real add_to_list and everywhere that refers to it. In the second case you're adding a new list containing None each time, and modifying different lists each time through

Python - external variable being changed by function

I am trying to write a function that squares each value in a list, returning a new list with individual values squared. I pass a list to it and it changes the original list. I'd like it to not make any changes to the original list, so that I can use it in other functions.
def squareset(c):
d=c
count = len(c)
print(c)
for i in range(0,(count),1):
d[i]=d[i]**2
return d
test = [1,2,3]
print(squareset(test))
print(test)
I don't have this problem with functions operating on simple variables of type int or float.
I added the d=c line trying to prevent the change to the list test, but it makes no difference. print(test) is producing the result [1,4,9] instead of [1,2,3]. Why is this happening and how can I fix this?
Doing d=c simply makes the parameter d point to the same object that c is pointing to. Hence, every change made to d is made to the same object that c points to.
If you want to avoid changing c you'll have to either send a copy of the object, or make a copy of the object inside the function and use this copy.
For example, do:
d = [i for i in c]
or:
d = c[:]
instead of:
d = c
Assigning the list to another variable doesn't copy the list. To copy, just
def squareset(c):
d=c[:]
...
While the other answers provided are correct I would suggest using list comprehension to square your list.
In [4]:
test = [1,2,3]
results = [elm**2 for elm in test]
print test
print results
[1, 2, 3]
[1, 4, 9]
If you wanted a function:
def squareList(lst):
return [elm**2 for elm in lst]
Try this:
def square(var):
return [x*x for x in var]
x = [1,2,3]
z = square(x)

What does [u'abcd', u'bcde'] mean in Python?

Used a loop to add a bunch of elements to a list with
mylist = []
for x in otherlist:
mylist.append(x[0:5])
But instead of the expected result ['x1','x2',...], I got: [u'x1', u'x2',...]. Where did the u's come from and why? Also is there a better way to loop through the other list, inserting the first six characters of each element into a new list?
The u means unicode, you probably will not need to worry about it
mylist.extend(x[:5] for x in otherlist)
The u means unicode. It's Python's internal string representation (from version ... ?).
Most times you don't need to worry about it. (Until you do.)
The answers above me already answered the "u" part - that the string is encoded in Unicode. About whether there's a better way to extract the first 6 letters from the items in a list:
>>> a = ["abcdefgh", "012345678"]
>>> b = map(lambda n: n[0:5], a);
>>> for x in b:
print(x)
abcde
01234
So, map applies a function (lambda n: n[0:5]) to each element of a and returns a new list with the results of the function for every element. More precisely, in Python 3, it returns an iterator, so the function gets called only as many times as needed (i.e. if your list has 5000 items, but you only pull 10 from the result b, lambda n: n[0:5] gets called only 10 times). In Python2, you need to use itertools.imap instead.
>>> a = [1, 2, 3]
>>> def plusone(x):
print("called with {}".format(x))
return x + 1
>>> b = map(plusone, a)
>>> print("first item: {}".format(b.__next__()))
called with 1
first item: 2
Of course, you can apply the function "eagerly" to every element by calling list(b), which will give you a normal list with the function applied to each element on creation.
>>> b = map(plusone, a)
>>> list(b)
called with 1
called with 2
called with 3
[2, 3, 4]

Categories