python evaluate bool within a list comprehension - python

Can I evaluate a bool within a list comprehension?
I would like to create a list that does not contain items that end with '.zip':
outlist = [x for x in os.listdir(path) if x *DOES NOT* end with '.zip']
I've used list comprehension for the exact opposite:
outlist2 = [x for x in os.listdir(path) if x.endswith('.zip')]
here is the outout of my list
os.listdir(path):
[
'sample1.zip', 'sample2.zip', 'sample3.zip', 'sample4.zip',
'sample1.txt', 'sample2.pdf', 'sample3.csv', 'sample4.xlsx'
]

Just add not:
outlist2 = [x for x in os.listdir(path) if not x.endswith('.zip')]
The if expression can be any valid Python expression, including one that uses boolean operators.
Demo:
>>> sample = ['sample1.zip', 'sample2.zip', 'sample3.zip', 'sample4.zip',
... 'sample1.txt', 'sample2.pdf', 'sample3.csv', 'sample4.xlsx']
>>> [x for x in sample if not x.endswith('.zip')]
['sample1.txt', 'sample2.pdf', 'sample3.csv', 'sample4.xlsx']

Sure you can - just slap a not operator in there:
outlist2 = [x for x in os.listdir(path) if not x.endswith('.zip')]

Related

Python - filter list from another other list with condition

list1 = ['/mnt/1m/a_pre.geojson','/mnt/2m/b_pre.geojson']
list2 = ['/mnt/1m/a_post.geojson']
I have multiple lists and I want to find all the elements of list1 which do not have entry in list2 with a filtering condition.
The condition is it should match 'm' like 1m,2m.. and name of geojson file excluding 'pre or post' substring.
For in e.g. list1 '/mnt/1m/a_pre.geojson' is processed but '/mnt/2m/b_pre.geojson' is not so the output should have a list ['/mnt/2m/b_pre.geojson']
I am using 2 for loops and then splitting the string which I am sure is not the only one and there might be easier way to do this.
for i in list1:
for j in list2:
pre_tile = i.split("/")[-1].split('_pre', 1)[0]
post_tile = j.split("/")[-1].split('_post', 1)[0]
if pre_tile == post_tile:
...
I believe you have similar first part of the file paths. If so, you can try this:
list1 = ['/mnt/1m/a_pre.geojson','/mnt/2m/b_pre.geojson']
list2 = ['/mnt/1m/a_post.geojson']
res = [x for x in list1 if x[:7] not in [y[:7] for y in list2]]
res:
['/mnt/2m/b_pre.geojson']
If I understand you correctly, using a regular expression to do this kind of string manipulation can be fast and easy.
Additionally, to do multiple member-tests in list2, it's more efficient to convert the list to a set.
import re
list1 = ['/mnt/1m/a_pre.geojson', '/mnt/2m/b_pre.geojson']
list2 = ['/mnt/1m/a_post.geojson']
pattern = re.compile(r'(.*?/[0-9]m/.*?)_pre.geojson')
set2 = set(list2)
result = [
m.string
for m in map(pattern.fullmatch, list1)
if m and f"{m[1]}_post.geojson" not in set2
]
print(result)

Create a list of consequential alphanumeric elements

I have
char=str('DOTR')
and
a=range(0,18)
How could I combine them to create a list with:
mylist=['DOTR00','DOTR01',...,'DOTR17']
If I combine them in a for loop then I lose the leading zero.
Use zfill:
>>> string = "DOTR"
>>> for i in range(0, 18):
... print("DOTR{}".format(str(i).zfill(2)))
...
DOTR00
DOTR01
DOTR02
DOTR03
DOTR04
DOTR05
DOTR06
DOTR07
DOTR08
DOTR09
DOTR10
DOTR11
DOTR12
DOTR13
DOTR14
DOTR15
DOTR16
DOTR17
>>>
And if you want a list:
>>> my_list = ["DOTR{}".format(str(i).zfill(2)) for i in range(18)]
>>> my_list
['DOTR00', 'DOTR01', 'DOTR02', 'DOTR03', 'DOTR04', 'DOTR05', 'DOTR06', 'DOTR07', 'DOTR08', 'DOTR09', 'DOTR10', 'DOTR11', 'DOTR12', 'DOTR13', 'DOTR14', 'DOTR15', 'DOTR16', 'DOTR17']
>>>
You can do it using a list comprehension like so:
>>> mylist = [char+'{0:02}'.format(i) for i in a]
>>> mylist
['DOTR00', 'DOTR01', 'DOTR02', 'DOTR03', 'DOTR04', 'DOTR05', 'DOTR06', 'DOTR07', 'DOTR08', 'DOTR09', 'DOTR10', 'DOTR11', 'DOTR12', 'DOTR13', 'DOTR14', 'DOTR15', 'DOTR16', 'DOTR17']
Simply use list comprehension and format:
mylist = ['DOTR%02d'%i for i in range(18)]
Or given that char and a are variable:
mylist = ['%s%02d'%(char,i) for i in a]
You can, as #juanpa.arrivillaga also specify it as:
mylist = ['{}{:02d}'.format(char,i) for i in a]
List comprehension is a concept where you write an expression:
[<expr> for <var> in <iterable>]
Python iterates over the <iterable> and unifies it with <var> (here i), next it calls the <expr> and the result is appended to the list until the <iterable> is exhausted.
can do like this
char = str('DOTR')
a=range(0,18)
b = []
for i in a:
b.append(char + str(i).zfill(2))
print(b)

String matching in lists - Python

I have a list like below - from this i have filter the tables that begin with 'test:SF.AcuraUsage_' (string matching)
test:SF.AcuraUsage_20150311
test:SF.AcuraUsage_20150312
test:SF.AcuraUsage_20150313
test:SF.AcuraUsage_20150314
test:SF.AcuraUsage_20150315
test:SF.AcuraUsage_20150316
test:SF.AcuraUsage_20150317
test:SF.ClientUsage_20150318
test:SF.ClientUsage_20150319
test:SF.ClientUsage_20150320
test:SF.ClientUsage_20150321
I am using this for loop but not sure why it does not work:
for x in list:
if(x 'test:SF.AcuraUsage_'):
print x
I tried this out:
for x in list:
alllist = x
vehiclelist = [x for x in alllist if x.startswith('geotab-bigdata-test:StoreForward.VehicleInfo')]
Still i get the error ' dictionary object has no attribute startswith'.
You shouldn't name your list list, since it overrides the built-in type list
But, if you'd like to filter that list using Python, consider using this list comprehension:
acura = [x for x in list if x.startswith('test:SF.AcuraUsage')]
then, if you'd like to output it
for x in acura:
print(x)
List comprehensions are good for that.
Get a list with all the items that begin with 'test:SF.AcuraUsage_' :
new_list = [x for x in list if x.startswith('test:SF.AcuraUsage_' ')]
Or the items that do not begin with 'test:SF.AcuraUsage_' :
new_list = [x for x in list if not x.startswith('test:SF.AcuraUsage_' )]
using re module:
import re
for x in list:
ret = re.match('test:SF.AcuraUsage_(.*)',x)
if ret:
print(re.group())

Python - Concatenate an item from a list with an item from another list

I need to concatenate an item from a list with an item from another list. In my case the item is a string (a path more exactly). After the concatenation I want to obtain a list with all the possible items resulted from concatenation.
Example:
list1 = ['Library/FolderA/', 'Library/FolderB/', 'Library/FolderC/']
list2 = ['FileA', 'FileB']
I want to obtain a list like this:
[
'Library/FolderA/FileA',
'Library/FolderA/FileB',
'Library/FolderB/FileA',
'Library/FolderB/FileB',
'Library/FolderC/FileA',
'Library/FolderC/FileB'
]
Thank you!
In [11]: [d+f for (d,f) in itertools.product(list1, list2)]
Out[11]:
['Library/FolderA/FileA',
'Library/FolderA/FileB',
'Library/FolderB/FileA',
'Library/FolderB/FileB',
'Library/FolderC/FileA',
'Library/FolderC/FileB']
or, slightly more portably (and perhaps robustly):
In [16]: [os.path.join(*p) for p in itertools.product(list1, list2)]
Out[16]:
['Library/FolderA/FileA',
'Library/FolderA/FileB',
'Library/FolderB/FileA',
'Library/FolderB/FileB',
'Library/FolderC/FileA',
'Library/FolderC/FileB']
You can use a list comprehension:
>>> [d + f for d in list1 for f in list2]
['Library/FolderA/FileA', 'Library/FolderA/FileB', 'Library/FolderB/FileA', 'Library/FolderB/FileB', 'Library/FolderC/FileA', 'Library/FolderC/FileB']
You may want to use os.path.join() instead of simple concatenation though.
The built-in itertools module defines a product() function for this:
import itertools
result = itertools.product(list1, list2)
The for loop can do this easily:
my_list, combo = [], ''
list1 = ['Library/FolderA/', 'Library/FolderB/', 'Library/FolderC/']
list2 = ['FileA', 'FileB']
for x in list1:
for y in list2:
combo = x + y
my_list.append(combo)
return my_list
You can also just print them:
list1 = ['Library/FolderA/', 'Library/FolderB/', 'Library/FolderC/']
list2 = ['FileA', 'FileB']
for x in list1:
for y in list2:
print str(x + y)

List Comprehensions and Conditions?

I am trying to see if I can make this code better using list comprehensions.
Lets say that I have the following lists:
a_list = [
'HELLO',
'FOO',
'FO1BAR',
'ROOBAR',
'SHOEBAR'
]
regex_list = [lambda x: re.search(r'FOO', x, re.IGNORECASE),
lambda x: re.search(r'RO', x, re.IGNORECASE)]
I basically want to add all the elements that do not have any matches in the regex_list into another list.
E.g. ==>
newlist = []
for each in a_list:
for regex in regex_list:
if(regex(each) == None):
newlist.append(each)
How can I do this using list comprehensions? Is it even possible?
Sure, I think this should do it
newlist = [s for s in a_list if not any(r(s) for r in regex_list)]
EDIT: on closer inspection, I notice that your example code actually adds to the new list each string in a_list that doesn't match all the regexes - and what's more, it adds each string once for each regex that it doesn't match. My list comprehension does what I think you meant, which is add only one copy of each string that doesn't match any of the regexes.
I'd work your code down to this:
a_list = [
'HELLO',
'FOO',
'FO1BAR',
'ROOBAR',
'SHOEBAR'
]
regex_func = lambda x: not re.search(r'(FOO|RO)', x, re.IGNORECASE)
Then you have two options:
Filter
newlist = filter(regex_func, a_list)
List comprehensions
newlist = [x for x in a_list if regex_func(x)]

Categories

Resources