Python: How to reference an object from the any() iterable - python

I'm trying to reference an object that I'm matching for.
import re
list = ["abc","b","c"]
if any(re.search(r"a",i) for i in list):
print("yes")
print(i)
This works, just not the last print command.
Is there any way to do what I'm trying do to here?

any only tells you whether anything fulfilled the condition, it doesn't let you have the value. The most pythonic way to do that is probably this:
try:
i = next(i for i in list if i == 'a')
print(i)
except StopIteration:
print('No such thing')
If you don't like the exception and would rather use an if:
i = next((i for i in list if i == 'a'), None)
if i:
print(i)

Variables from any() do not bleed out of it's scope - they are only known inside it.
You are just matching simple letters - you can get all items from your list that have this letter in them by using a list comprehension:
my_list = ["abc","b","c","abracadabra"]
with_a = [ item for item in my_list if "a" in item] # or re.find ... but not needed here
# this prints all of them - you can change it to if ...: and print(with_a[0])
# to get only the first occurence
for item in with_a:
print("yes")
print(item)
Output:
yes
abc
yes
abracadabra

Related

Converting string values to float and removing strings from list

I have a list that looks like this
lst = ['a','b','43.23','c','9','22']
I would like to remove the elements that cannot be represented as floats and hence I am doing the following (Attempt 1):
for i,j in enumerate(lst):
try:
lst[i]=float(j)
except:
lst.remove(j)
Which leaves the list looking like this
lst = ['b', 43.23, '9', 22.0]
whereas what I need is this
lst = [43.23, 9.0 , 22.0]
And so I'm doing the following:
for i,j in enumerate(lst):
try:
lst[i]=float(j)
except:
pass
lst = [i for i in lst if type(i) != str]
Is there a cleaner way to do this.?
EDIT: Changed the name of example list from 'list' to 'lst' based on the recommendations below.
You can use the following function from this stackoverflow post:
def isfloat(value):
try:
float(value)
return True
except ValueError:
return False
And, then use it in a list comprehension:
>>> l = ['a','b','43.23','c','9','22']
>>> [float(x) for x in l if isfloat(x)]
# [43.23, 9.0, 22.0]
First you shouldn't name your variable list it will shadow the built-in list function/class. You can use a simple function to do this:
>>> lst = ['a','b','43.23','c','9','22']
>>> def is_float(el):
... try:
... return float(el)
... except ValueError:
... pass
...
>>> [i for i in lst if is_float(i)]
['43.23', '9', '22']
>>> [float(i) for i in lst if is_float(i)] # to return a list of floating point number
[43.23, 9.0, 22.0]
The problem with your code is that you are trying to modify your list while iterating. Instead you can make a copy of your list then use the element index to remove their value.
lst = ['a','b','43.23','c','9','22']
lst_copy = lst.copy()
for el in lst:
try:
float(val)
except ValueError:
lst_copy.remove(el)
Of course this is less efficient than the solution using the list comprehension with a predicate because you first need to make a copy of your original list.
You shouldn't manipulate the list you're iterating through (and you shouldn't call it list neither, since you would shadow the built-in list), since that messes up with the indexes.
The reason why 'b' shows up in your output is that during the first iteration, 'a' is not a float, so it gets removed. Thus your list becomes:
['b','43.23','c','9','22']
and b becomes list[0]. However, the next iteration calls list[1] skipping thus 'b'.
To avoid such an issue, you can define a second list and append the suitable values to that:
l1 = ['a','b','43.23','c','9','22']
l2 = []
for item in l1:
try:
l2.append(float(item))
except ValueError: # bare exception statements are bad practice too!
pass
Would be better in considering iterators to efficiently use system memory. Here is my take to the solution.
def func(x):
try:
return float(x)
except ValueError:
pass
filter(lambda x: x, map(func, li))
Borrowing idea from this post : python: restarting a loop, the first attempt can be fixed with a simple while loop
lst = ['a','b','43.23','c','9','22']
temp = 0
while temp<len(lst):
try:
lst[temp] = float(lst[temp])
temp+=1
except ValueError:
lst.remove(lst[temp])
temp = 0
which leaves me with the desired result (by resetting the loop iterator)
lst = [43.23, 9.0 , 22.0]

Check if item is member of list of objects

I'm looking for a clean way to check if an item is member of a list of objects.
Basically this is what I want to do:
class Constant:
def __init__(self,name,value):
self.name = name
self.value = value
list = [Constant('el1',1),Constant('el2',2)]
list2= ['el4','el5','el1']
for item in list2:
#clean solution for this if clause is needed (I'm aware list.name triggers an error)
if item in list.name:
print 'it is a member'
So it is important to me that the item matches only on the name, the value has no meaning when searching. I know I can solve this by adding an additional for loop like this:
for item in list2:
for itemConstant in list:
if item == itemConstant.name:
print 'it is a member'
But I want to be sure there is no better solution than this.
You can use any:
for item in list2:
if any(item == c.name for c in list):
print 'it is a member'
Since the value has no meaning use a set with in as strings are hashable and you will have a 0(1) lookups, storing the names from the instances in a set:
st = {Constant('el1',1).name,Constant('el2',2).name}
lst2 = ['el4','el5','el1']
for c in lst2:
if c in st:
print('it is a member')
Or make lst2 a set:
lst = [Constant('el1',1), Constant('el2',2)]
st = {'el4','el5','el1'}
for c in lst:
if c.name in st:
print(c.name)
I presume you want exact matches as "foo" in "foobar" would be True.
You can also leave the original list as is an create a set from the instance names:
lst = [Constant('el1', 1), Constant('el2', 2)]
lst2 = ['el4', 'el5', 'el1']
st = {c.name for c in lst}
for c in lst2:
if c in st:
print('it is a member')
So you still have an 0(n) solution as it just requires one more pass over your instances lst.
Make list2 a set and loop over your list of constants to test each against that set. Use the any() callable to exit early when a match is found:
constants = [Constant('el1', 1), Constant('el2',2)]
elements = {'el4', 'el5', 'el1'}
if any(c.name in elements for c in constants):
print 'is a member'
This reduces the problem to one loop; membership testing against a set is a O(1) constant time operation on average. The loop is exited early when a match is found, further reducing the number of tests made.

Uniqueify returning a empty list

I'm new to python and trying to make a function Uniqueify(L) that will be given either a list of numbers or a list of strings (non-empty), and will return a list of the unique elements of that list.
So far I have:
def Uniquefy(x):
a = []
for i in range(len(x)):
if x[i] in a == False:
a.append(x[i])
return a
It looks like the if str(x[i]) in a == False: is failing, and that's causing the function to return a empty list.
Any help you guys can provide?
Relational operators all have exactly the same precedence and are chained. This means that this line:
if x[i] in a == False:
is evaluated as follows:
if (x[i] in a) and (a == False):
This is obviously not what you want.
The solution is to remove the second relational operator:
if x[i] not in a:
You can just create a set based on the list which will only contain unique values:
>>> s = ["a", "b", "a"]
>>> print set(s)
set(['a', 'b'])
The best option here is to use a set instead! By definition, sets only contain unique items and putting the same item in twice will not result in two copies.
If you need to create it from a list and need a list back, try this. However, if there's not a specific reason you NEED a list, then just pass around a set instead (that would be the duck-typing way anyway).
def uniquefy(x):
return list(set(x))
You can use the built in set type to get unique elements from a collection:
x = [1,2,3,3]
unique_elements = set(x)
You should use set() here. It reduces the in operation time:
def Uniquefy(x):
a = set()
for item in x:
if item not in a:
a.add(item)
return list(a)
Or equivalently:
def Uniquefy(x):
return list(set(x))
If order matters:
def uniquefy(x):
s = set()
return [i for i in x if i not in s and s.add(i) is None]
Else:
def uniquefy(x):
return list(set(x))

Python 3 How to check if a value is already in a list in a list

I have a list of lists in my Python 3:
mylist = [[a,x,x][b,x,x][c,x,x]]
(x is just some data)
I have my code which does that:
for sublist in mylist:
if sublist[0] == a:
sublist[1] = sublist[1]+1
break
now I want to add an entry, if there is any sublistentry ==a
How can I do that?
Use any() to test the sublists:
if any(a in subl for subl in mylist):
This tests each subl but exits the generator expression loop early if a match is found.
This does not, however, return the specific sublist that matched. You could use next() with a generator expression to find the first match:
matched = next((subl for subl in mylist if a in subl), None)
if matched is not None:
matched[1] += 1
where None is a default returned if the generator expression raises a StopIteration exception, or you can omit the default and use exception handling instead:
try:
matched = next(subl for subl in mylist if a in subl)
matched[1] += 1
except StopIteration:
pass # no match found
You could use any() with list comprehensions (well, generator comprehensions here):
inList = any(a in sublist for sublist in mylist)

How to get item's position in a list?

I am iterating over a list and I want to print out the index of the item if it meets a certain condition. How would I do this?
Example:
testlist = [1,2,3,5,3,1,2,1,6]
for item in testlist:
if item == 1:
print position
Hmmm. There was an answer with a list comprehension here, but it's disappeared.
Here:
[i for i,x in enumerate(testlist) if x == 1]
Example:
>>> testlist
[1, 2, 3, 5, 3, 1, 2, 1, 6]
>>> [i for i,x in enumerate(testlist) if x == 1]
[0, 5, 7]
Update:
Okay, you want a generator expression, we'll have a generator expression. Here's the list comprehension again, in a for loop:
>>> for i in [i for i,x in enumerate(testlist) if x == 1]:
... print i
...
0
5
7
Now we'll construct a generator...
>>> (i for i,x in enumerate(testlist) if x == 1)
<generator object at 0x6b508>
>>> for i in (i for i,x in enumerate(testlist) if x == 1):
... print i
...
0
5
7
and niftily enough, we can assign that to a variable, and use it from there...
>>> gen = (i for i,x in enumerate(testlist) if x == 1)
>>> for i in gen: print i
...
0
5
7
And to think I used to write FORTRAN.
What about the following?
print testlist.index(element)
If you are not sure whether the element to look for is actually in the list, you can add a preliminary check, like
if element in testlist:
print testlist.index(element)
or
print(testlist.index(element) if element in testlist else None)
or the "pythonic way", which I don't like so much because code is less clear, but sometimes is more efficient,
try:
print testlist.index(element)
except ValueError:
pass
Use enumerate:
testlist = [1,2,3,5,3,1,2,1,6]
for position, item in enumerate(testlist):
if item == 1:
print position
for i in xrange(len(testlist)):
if testlist[i] == 1:
print i
xrange instead of range as requested (see comments).
Here is another way to do this:
try:
id = testlist.index('1')
print testlist[id]
except ValueError:
print "Not Found"
Try the below:
testlist = [1,2,3,5,3,1,2,1,6]
position=0
for i in testlist:
if i == 1:
print(position)
position=position+1
[x for x in range(len(testlist)) if testlist[x]==1]
If your list got large enough and you only expected to find the value in a sparse number of indices, consider that this code could execute much faster because you don't have to iterate every value in the list.
lookingFor = 1
i = 0
index = 0
try:
while i < len(testlist):
index = testlist.index(lookingFor,i)
i = index + 1
print index
except ValueError: #testlist.index() cannot find lookingFor
pass
If you expect to find the value a lot you should probably just append "index" to a list and print the list at the end to save time per iteration.
I think that it might be useful to use the curselection() method from thte Tkinter library:
from Tkinter import *
listbox.curselection()
This method works on Tkinter listbox widgets, so you'll need to construct one of them instead of a list.
This will return a position like this:
('0',) (although later versions of Tkinter may return a list of ints instead)
Which is for the first position and the number will change according to the item position.
For more information, see this page:
http://effbot.org/tkinterbook/listbox.htm
Greetings.
Why complicate things?
testlist = [1,2,3,5,3,1,2,1,6]
for position, item in enumerate(testlist):
if item == 1:
print position
Just to illustrate complete example along with the input_list which has searies1 (example: input_list[0]) in which you want to do a lookup of series2 (example: input_list[1]) and get indexes of series2 if it exists in series1.
Note: Your certain condition will go in lambda expression if conditions are simple
input_list = [[1,2,3,4,5,6,7],[1,3,7]]
series1 = input_list[0]
series2 = input_list[1]
idx_list = list(map(lambda item: series1.index(item) if item in series1 else None, series2))
print(idx_list)
output:
[0, 2, 6]
l = list(map(int,input().split(",")))
num = int(input())
for i in range(len(l)):
if l[i] == num:
print(i)
Explanation:
Taken a list of integer "l" (separated by commas) in line 1.
Taken a integer "num" in line 2.
Used for loop in line 3 to traverse inside the list and checking if numbers(of the list) meets the given number(num) then it will print the index of the number inside the list.
testlist = [1,2,3,5,3,1,2,1,6]
num = 1
for item in range(len(testlist)):
if testlist[item] == num:
print(item)
testlist = [1,2,3,5,3,1,2,1,6]
for id, value in enumerate(testlist):
if id == 1:
print testlist[id]
I guess that it's exacly what you want. ;-)
'id' will be always the index of the values on the list.

Categories