This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Return the first item in a list matching a condition
How to easily grab the "matching" list element using list comprehension? e.g. I've a list and I'm looking for a element that starts with a a certain string. That's easy to do:
>>> lines = ['AHP Buildlife number', 'NIT-Version-Default-v0.16.0', 'E_release v2.3.14.0']
>>> [ x.strip() for x in lines if x.startswith('NIT-Version-Default') ]
['NIT-Version-Default-v0.16.0']
But how can I do the same from in a if statement so that the matching list-element can be used for further processing; some thing like this:
>>> if [ x.strip() for x in lines if x.startswith('NSS-Checkin-Default') ]:
... ver = x.split('-')[-1].strip()
... print ver
So, that it return v0.16.0 as the version number. This obviously doesn't work but hopefully you get the idea what I'm trying to do. Any idea how to do that? Cheers!!
PS. You are welcome to improve the question or the title.
If you're looking for only one element:
x = next(x.strip() for x in lines if x.startswith('NSS-Checkin-Default'))
ver = x.split('-')[-1].strip()
Note that I've used a generator expression (a for b in c if d), instead a list comprehension [a for b in c if d]. This way the iteration over lines will only be done for as long as actually needed (in this case, until the first element is found).
If no element is found, next will raise StopIteration.
If you additionally want to make sure that there's exactly one element (or exactly N elements for some fixed N), you could write it this way (assign to a tuple):
(x,) = (x.strip() for x in lines if x.startswith('NSS-Checkin-Default')
In that case you'll have a ValueError if the generator expression will yield too few or too many elements. This is called "tuple unpacking".
See also:
What is the best way to get the first item from an iterable matching a condition?
Simple: your list comprehension returns a list with one element, so you just access the element: thelist[0]
To take from your example:
lines = ['AHP Buildlife number', 'NIT-Version-Default-v0.16.0', 'E_release v2.3.14.0']
results = [ x.strip() for x in lines if x.startswith('NIT-Version-Default') ]
ver = results[0].split('-')[-1].strip()
print ver
See the map function. I don't see a vital necessity of comprehensions, instead:
map(lambda x: x.split('-')[-1].strip(),
filter(lambda x: x.startswith('NIT'), lines))
>>> for each in lines:
... match=re.search("(^NIT-Version-Default).*(v[0-9.]+)",each)
... if match:
... print match.group(2)
...
v0.16.0
Related
This question already has answers here:
Slicing out a specific from a list
(2 answers)
Index all *except* one item in python
(11 answers)
Closed 2 years ago.
Is it possible to use slice but on a specific element on a list? For example a = [1,2,3,4,5,6,7,8,9] I want to make a for loop that prints out the whole list except the second element.
I want to make something like this:
for i in a[something_slice]:
print(i)
Is this possible?
For excluding just one element, the 2 slice lst[:i] + lst[i + 1:] approach proposed by #Applet123 is probably the fastest (Or perhaps a excluded = lst.pop(1) to extract the excluded element and for x in lst: print(x) for printing all the others; then lst.insert(1,excluded) to put the excluded element back on the list. See data structures docs for details).
If you just want to filter out certain indexes, instead of a for loop I recommend you use a more pythonic (and intuitive) approach based on list comprehensions and enumerate:
myList = [1,2,3,4,5,6,7,8,9]
excludedIndices = [1]
myFilteredList = [x for i, x in enumerate(myList) if i not in excludedIndices]
print (myFilteredList)
# output:
# [1,3,4,5,6,7,8,9]
# or, to actually print each element individually:
for x in myFilteredList:
print (x)
# which can also work as a 2-liner with inline filtering:
for i, x in enumerate(myList):
if i not in excludedIndices: print(x)
Also check out python usage of filter and map builtin functions, which may be overkill for this purpose but still offer a general and more powerful solution for this kind of processing:
# filters an enumerated element
def myFilter(element):
return element[0] not in excludedIndices
# maps an enumerated element to a function
def myMap(element):
print(element[1])
# runs myMap function for each enumerated element on the list filtered by myFilter
for x in map(myMap,filter(myFilter,enumerate(myList))): pass
Which you can also turn into a one-liner using lambda expressions:
for x in map(lambda x: print(x[1]),filter(lambda x: x[0] not in excludedIndices,enumerate(myList))): pass
you can do it without slicing, using enumerate()
index_to_skip=1
for idx,item in enumerate(a):
if idx!=index_to_skip:
print(item)
If you actually want to slice the list, you can use 2 slices to slice around it:
def exclude(lst, i):
return lst[:i] + lst[i + 1:]
exclude([1, 2, 3, 4, 5], 1) # [1, 3, 4, 5]
If you just want to loop through it, you could alternatively just skip when the index reaches the value you want to skip:
for i, v in enumerate(a):
if i == 1:
continue
print(v)
I have a python list which looks like this :
['NEW:kim:OPERATOR', 'DELETE:joe:USER_ROLE_GUEST']
Currently I am accessing specific portions of each element of the list like NEW or joe by splitting each element by : creating a list of list like :
[['NEW','kim','OPERATOR'], ['DELETE','joe','USER_ROLE_GUEST']]
and then accessing it like list[i][j].
Is there any nice pythonic way of avoiding all this and directly accessing the elements that I need ?
If your purpose (which is not clear) is to not create a new list (which may be costly if the original list is large), and the data structure is always the same, you could split the internal string on the fly:
a = ['NEW:kim:OPERATOR', 'DELETE:joe:USER_ROLE_GUEST']
a[0].split(":")[0] # returns NEW
By the way, transforming your list in a list of tuples (or better, namedtuples) would be a better approach from a programming POV.
You can use the following function :
>>> def find_element(i,j,li):
... try:
... return li[i].split(':')[j]
... except IndexError:
... print 'your index is out of range'
...
>>> l =['NEW:kim:OPERATOR', 'DELETE:joe:USER_ROLE_GUEST']
>>> find_element(1,4,l)
your index is out of range
>>> find_element(1,2,l)
'USER_ROLE_GUEST'
You could use a generator expression and pop the elements of as needed:
l = ['NEW:kim:OPERATOR', 'DELETE:joe:USER_ROLE_GUEST']
spl = (sub.split(":") for sub in l)
a = next(spl)
print(a[0])
b = next(spl)
print(b[0])
Or simply a generator expression and iterate over:
spl = (sub.split(":") for sub in l)
for ele in spl:
print(ele)
['NEW', 'kim', 'OPERATOR']
['DELETE', 'joe', 'USER_ROLE_GUEST']
I have a list which has the following structure:
a = [[1,'a'], [2,'b'], [3,'c']]
I would like to create a range of the first element in every sub-list without making a second for-loop. I was thinking about something like this:
for i in a[][0]:
print i
However, the above last code does not work (SyntaxError: invalid syntax). Any idea if it's possible to do this in Python?
EDIT:
The output I would like to get with the above loop is:
1
2
3
and not
1
a
for sublist in a:
print sublist[0]
To build a list of first items, use list comprehension:
first_items = [sublist[0] for sublist in a]
for i,_ in a:
print i
should do the trick
This is probably overkill for such a simple example, but for variety:
for i in map(operator.itemgetter(0), a):
print i
In Python 2 map builds the whole list of first elements. You could use itertools.imap to avoid that. Of course for 3 elements it doesn't matter anyway.
I mention this because it's more flexible than for i, _ in a (there don't need to be exactly two elements in each sublist) and it gives you the i you want instead of doing for i in a and using i[0] (perhaps multiple times in a less simple example). But of course you could just as easily get the i you want with:
for l in a:
i = l[0]
print i
... not everything needs to be done in the loop header, it's just nice that it can be :-)
>>> a = [[1,'a'], [2,'b'], [3,'c']]
>>> for i in a:
... print i[0]
...
1
2
3
I think this method is kind of close to what you were trying.
>>> a = [[1,'a'], [2,'b'], [3,'c']]
>>> for [x,y] in a:
... print(x)
...
1
2
3
However,if your lists are of unequal size, then #warwaruk's answer is better.
I am new in python, and while reading a BeautifulSoup tutorial, I didn't understand this expression "[x for x in titles if x.findChildren()][:-1]" that i didn't understand? can you explain it
titles = [x for x in titles if x.findChildren()][:-1]
To start with [:-1], this extracts a list that contains all elements except the last element.
>>> a=[1,2,3,4,5]
>>> a[:-1]
[1, 2, 3, 4]
The comes the first portion, that supplies the list to [:-1] (slicing in python)
[x for x in titles if x.findChildren()]
This generates a list that contains all elements (x) in the list "titles", that satisfies the condition (returns True for x.findChildren())
It's a list comprehension.
It's pretty much equivalent to:
def f():
items = []
for x in titles:
if x.findChildren():
items.append(x)
return items[:-1]
titles = f()
One of my favorite features in Python :)
The expression f(X) for X in Y if EXP is a list comprehension It will give you either a generator (if it's inside ()) or a list (if it's inside []) containing the result of evaluating f(X) for each element of Y, by only if EXP is true for that X.
In your case it will return a list containing every element from titles if the element has some children.
The ending [:-1] means, everything from the list apart from the last element.
It's called a for comprehension expression. It is simply constructing a list of all titles in the x list which return true when the findChildren function is called upon them. The final statement substracts the last one from the list.
List Comprehension for me seems to be like the opaque block of granite that regular expressions are for me. I need pointers.
Say, I have a 2D list:
li = [[0,1,2],[3,4,5],[6,7,8]]
I would like to merge this either into one long list
li2 = [0,1,2,3,4,5,6,7,8]
or into a string with separators:
s = "0,1,2,3,4,5,6,7,8"
Really, I'd like to know how to do both.
Like so:
[ item for innerlist in outerlist for item in innerlist ]
Turning that directly into a string with separators:
','.join(str(item) for innerlist in outerlist for item in innerlist)
Yes, the order of 'for innerlist in outerlist' and 'for item in innerlist' is correct. Even though the "body" of the loop is at the start of the listcomp, the order of nested loops (and 'if' clauses) is still the same as when you would write the loop out:
for innerlist in outerlist:
for item in innerlist:
...
Try that:
li=[[0,1,2],[3,4,5],[6,7,8]]
li2 = [ y for x in li for y in x]
You can read it like this:
Give me the list of every ys.
The ys come from the xs.
The xs come from li.
To map that in a string:
','.join(map(str,li2))
There's a couple choices. First, you can just create a new list and add the contents of each list to it:
li2 = []
for sublist in li:
li2.extend(sublist)
Alternately, you can use the itertools module's chain function, which produces an iterable containing all the items in multiple iterables:
import itertools
li2 = list(itertools.chain(*li))
If you take this approach, you can produce the string without creating an intermediate list:
s = ",".join(itertools.chain(*li))
My favorite, and the shortest one, is this:
li2 = sum(li, [])
and
s = ','.join(li2)
EDIT: use sum instead of reduce, (thanks Thomas Wouters!)
For the second one, there is a built-in string method to do that :
>>> print ','.join(str(x) for x in li2)
"0,1,2,3,4,5,6,7,8"
For the first one, you can use join within a comprehension list :
>>> print ",".join([",".join(str(x) for x in li])
"0,1,2,3,4,5,6,7,8"
But it's easier to use itertools.flatten :
>>> import itertools
>>> print itertools.flatten(li)
[0,1,2,3,4,5,6,7,8]
>>> print ",".join(str(x) for x in itertools.flatten(li))
"0,1,2,3,4,5,6,7,8"
N.B : itertools is a module that help you to deal with common tasks with iterators such as list, tuples or string... It's handy because it does not store a copy of the structure you're working on but process the items one by one.
EDIT : funny, I am learning plenty of way to do it. Who said that there was only one good way to do it ?
import itertools
itertools.flatten( li )
To make it a flattened list use either:
http://code.activestate.com/recipes/121294/
http://code.activestate.com/recipes/363051/
Then, join to make it a string.
Here is a way:
def convert2DArrtostring(ndArr):
'''converts 2D array to string'''
arr_str = "["
for i in ndArr:
arr_str += "["
for j in i:
arr_str += str(j) + " "
arr_str += "]\n"
arr_str += "]"
return arr_str
There are many ways to do this problem. I like Numpy's tools because it is normally already imported in everything I do. However, if you aren't using Numpy for anything else this probably isn't a good method.
import numpy
li = [[0,1,2],[3,4,5],[6,7,8]]
li2=li[0] #first element of array to merge
i=1
while i<len(li):
li2=numpy.concatenate((li2,li[i]))
i+=1
print li2
This would print [0 1 2 3 4 5 6 7 8] and then you can convert this into your string too.