Is there a way to do the following in one line?
[del item for item in new_json if item['Country'] in countries_to_remove]
The above gives me a SyntaxError.
del is a statement and you cannot use that as an expression in list comprehenstion. That is why you are getting a SyntaxError.
You can use list comprehension to create a new list, without the elements you don't want, like this
[item for item in new_json if item['Country'] not in countries_to_remove]
This is actually equivalent to,
result = []
for item in new_json:
if item['Country'] not in countries_to_remove:
result.append(item)
This kind of operation is called filtering a list and you can use the builtin filter function, like this
list(filter(lambda x: x['Country'] not in countries_to_remove, new_json))
As suggested by mgilson in the comments section, if you just want to mutate the original list, then you can use slicing assignment, like this
new_json[:] = [x for x in new_json if x['Country'] not in countries_to_remove]
del is a statement in python, and you cannot have statements inside list comprehension (You can only have expressions there). Why not just create new_json as a new list or dictionary that does not include the items you want to delete. Example =
new_json = [item for item in new_json if item['Country'] not in countries_to_remove]
Related
I have the list that contains some items like:
"GFS01_06-13-2017 05-10-18-38.csv"
"Metadata_GFS01_06-13-2017 05-10-18-38.csv"
How to find the list item that start with "GFS01_"
In SQL I use query: select item from list where item like 'GFS01_%'
You have several options, but most obvious are:
Using list comprehension with a condition:
result = [i for i in some_list if i.startswith('GFS01_')]
Using filter (which returns iterator)
result = filter(lambda x: x.startswith('GFS01_'), some_list)
You should try something like this :
[item for item in my_list if item.startswith('GFS01_')]
where "my_list" is your list of items.
If you really want the string output like this "GFS01_06-13-2017 05-10-18-38.csv","GFS01_xxx-xx-xx.csv", you could try this:
', '.join([item for item in myList if item.startswith('GFS01_')])
Or with quotes
', '.join(['"%s"' % item for item in myList if item.startswith('GFS01_')])
Filtering of list will gives you list again and that needs to be handled as per you requirement then.
Recently I encountered this problem:
Say there is a list of something I want to process:
process_list=["/test/fruit/apple","/test/fruit/pineapple","/test/fruit/banana","/test/tech/apple-pen","/test/animal/python","/test/animal/penguin"]
And I want to exclude something using another list, for instance:
exclude_list=["apple","python"]
The process_list should be like this after I apply the exclude_list to it( any process_list item that contains a sub:
["/test/fruit/banana","/test/animal/penguin","/test/fruit/pineapple"]
or if the exclude_list is:
exclude_list=["pen","banana"]
The process_list should be this after apply the filter:
["/test/fruit/apple","/test/fruit/pineapple","/test/animal/python"]
So what I was trying at first was:
for item in exclude_list:
for name in (process_list):
if item in name:
process_list.remove(name)
Of course this didn't work because removing elements from the list while iterating over it using a for loop is not permitted. The code only removed the first match and then stopped.
So then I came up a way to do this with another list:
deletion_list=[] #Track names that need to be deleted
for item in exclude_list:
for name in (process_list):
if item in name:
deletion_list.append(name)
# A list comprehension
process_list=[ x for x in process_list if x not in deletion_list ]
It works, but my guts tell me there may be a more elegant way. Now it need s another list to store the name need to be deleted. Any ideas?
You may use the list comprehension expression using all() filter as:
# Here: `p` is the entry from `process_list`
# `e` is the entry from `exclude_list`
>>> [p for p in process_list if all(e not in p for e in exclude_list)]
['/test/fruit/banana', '/test/animal/penguin']
Regarding your statement:
Of course this didn't work because removing elements from the list while iterating over it using a for loop is not permitted. The code only removed the first match and then stopped.
You could have iterate over the copy of the list as:
for item in list(exclude_list): # OR, for item in exclude_list[:]:
# ^-- Creates new copy ----------------------------^
Just in addition you can also use regular expression e.g.
import re
pattern = '(' + ('|').join(exclude_list) + ')'
list(filter(lambda l : re.search(pattern,l) == None, process_list)) #filter will return iterator in case if you use python 3
Use os.path.basename to get the basename of pathname, use the build-in functon all to check if the basename is not included in exclude_list.
import os
process_list=["/test/fruit/apple","/test/fruit/pineapple","/test/fruit/banana","/test/tech/apple-pen","/test/animal/python","/test/animal/penguin"]
# Case 1
exclude_list=["apple","python"]
l = [s for s in process_list
if all(item not in os.path.basename(s) for item in exclude_list)]
print(l)
['/test/fruit/banana', '/test/animal/penguin']
# Case 2
exclude_list=["pen","banana"]
l = [s for s in process_list
if all(item not in os.path.basename(s) for item in exclude_list)]
print(l)
['/test/fruit/apple', '/test/fruit/pineapple', '/test/animal/python']
[line for line in lines if not any(word in line for word in words)]
Another approach to achieve what you want is as follows:
[item for item in process_list if not any(exc in item.split('/')[-1] for exc in exclude_list)]
Output:
>>> [item for item in process_list if not any(exc in item.split('/')[-1] for exc in exclude_list)]
['/test/fruit/banana', '/test/animal/penguin']
if you want to work directly with process_list and the list comprehension without any funny behavior you should work with a copy, which is created like this: process_list[:]
process_list=["/test/fruit/apple","/test/fruit/pineapple","/test/fruit/banana","/test/tech/apple-pen","/test/animal/python","/test/animal/penguin"]
exclude_list=["apple","python"]
process_list = [x for x in process_list[:] if not any(y in x for y in exclude_list)]
I have a list of record instances returned by SQLAlchemy.
While the instances have many attributes, I want a new list with only one of the attributes. The java coder in me says:
my_records = query.all()
names = []
for my_record in my_records:
names.append(my_record.name)
...which works, of course. But What's the Pythonic answer? I know there a one-liner that includes these 4 lines into 1, but finding it is like googling for "for".
You are looking for what is called a list comprehension:
names = [my_record.name for my_record in query.all()]
The above is a concise equivalent to the for-loop in your example.
In addition, you should be aware that there are dict comprehensions:
{key:val for key, val in iterable}
as well as set comprehensions:
{item for item in iterable}
which will construct new dictionaries and sets respectively.
Lastly, all of these constructs allow you to add an optional condition to be tested for each item:
[item for item in iterable if condition]
{key:val for key, val in iterable if condition}
{item for item in iterable if condition}
This is useful if you want to filter the items from the iterable by the condition.
You want to do a list comprehension:
result = [my_record['name'] for my_record in query.all()]
Alternatively to list comprehension you can use operator.attrgetter and map:
map(operator.attrgetter('name'), query.all())
(But the list comprehension variant is easier to read IMO.)
I have a list of strings, and calling a function on each string which returns a string. The thing I want is to update the string in the list. How can I do that?
for i in list:
func(i)
The function func() returns a string. i want to update the list with this string. How can it be done?
If you need to update your list in place (not create a new list to replace it), you'll need to get indexes that corresponds to each item you get from your loop. The easiest way to do that is to use the built-in enumerate function:
for index, item in enumerate(lst):
lst[index] = func(item)
You can reconstruct the list with list comprehension like this
list_of_strings = [func(str_obj) for str_obj in list_of_strings]
Or, you can use the builtin map function like this
list_of_strings = map(func, list_of_strings)
Note : If you are using Python 3.x, then you need to convert the map object to a list, explicitly, like this
list_of_strings = list(map(func, list_of_strings))
Note 1: You don't have to worry about the old list and its memory. When you make the variable list_of_strings refer a new list by assigning to it, the reference count of the old list reduces by 1. And when the reference count drops to 0, it will be automatically garbage collected.
First, don't call your lists list (that's the built-in list constructor).
The most Pythonic way of doing what you want is a list comprehension:
lst = [func(i) for i in lst]
or you can create a new list:
lst2 = []
for i in lst:
lst2.append(func(i))
and you can even mutate the list in place
for n, i in enumerate(lst):
lst[n] = func(i)
Note: most programmers will be confused by calling the list item i in the loop above since i is normally used as a loop index counter, I'm just using it here for consistency.
You should get used to the first version though, it's much easier to understand when you come back to the code six months from now.
Later you might also want to use a generator...
g = (func(i) for i in lst)
lst = list(g)
You can use map() to do that.
map(func, list)
In python, What is the most preferred (pythonic) way to do the following:
You are given a list. If the list is not empty, all items in the list are guaranteed to be strings. Each item in the list is either the empty string, or is guaranteed to return True if isdigit() is called on the item.
Starting with such a list, what is the most elegant way to end up with a list such that it has all items from the original list, except for the empty strings?
Using filter() with the default identity function (None):
newlist = filter(None, origlist)
alternatively, a list comprehension:
newlist = [el for el in origlist if el]