I'm working on a project in which I'm trying to utilize user input in order to search an attribute table for a city. If the city is not present in the table, I want to have a secondary response. So far, I've been using a searchCursor followed by a for loop and then an if statement. If I use a single If statement, I am able to achieve a single response. But if I include a second conditional statement, be it an elif an else or a second if, the script goes through the whole table and gives me a response for each row. Ideally, I would like it to give me a single response (ie. "Yes, its in the table", "No its not in the table"). I'm relatively new to arcGIS, and even newer to Python. Below is my sample text. Any help would be greatly appreciated.
#import necessary tools
import arcpy
from arcpy import env
import sys
#set workspace
arcpy.env.workspace = r'C:\Data' #generic source for data
#inquire user input
print "Please search for a city in New Mexico within 10 Miles of an Amtrak Station."
userInput = raw_input ("Which city would you like to check? ")
#establish the SearchCursor
citySearch = arcpy.da.SearchCursor('CitiesAmtrak.shp', 'NAME')
#create a loop to utilize SearchCursor and provide feedback
for column in citySearch:
if userInput in column:
print "This city is within 10 miles of an Amtrak Station."
break
if userInput not in column:
print "no"
line 21&22
else:
print("no")
you don't double check with 2 if statements
Even with an else statement, I still receive "no" returned for as many rows before the correct input, or for all the rows if the input is not in the table.
Oh I get it now. That is how search cursors work, one row at a time. You are looking for something that vectorizes stuff behinds the scenes. It exists (numpy, scipy) but the scene behind those scenes are the same just faster
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
_is_in(a, 3) # a function equivalent to for and if loop, but doesn't contain for or if
array([False, False, False, True, False, False, False, False, False, False], dtype=bool)
If depends on what is 'exposed' The above is a simple function (that doesn't contain a for or if) which returns the result seemingly automagically.
# how about....
a = [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
for i in a:
if i == 3:
val = 'found'
break
else:
val = 'not found'
print(result.format(val))
# result
The value is found
Thank you for your help, I really appreciate it. The script now will only give that the value is not found as an output. Regardless of whether the value should be found or not.
#inquire user input
print "Please search for a city in New Mexico within 10 Miles of an Amtrak Station."
userInput = raw_input ("Which city would you like to check? ")
#establish the SearchCursor
citySearch = arcpy.da.SearchCursor('CitiesAmtrak.shp', 'NAME')
#create a loop to utilize SearchCursor and provide feedback
for row in citySearch:
if row == userInput:
val = 'found'
break
else:
val = 'not found'
print "The Value is {1}.".format(val)
Oooo ugly text and case testing. IF you are working with text entry, you had better case everything to upper or lower case prior to doing the testing... and little things like a stray blank space at the beginning or end spell toast for any well intentioned programmer. And I am assuming that people know how to spell and a hundred other things. So make sure you test with something that is known
a = ['a', 'b', 'bb', 'A', 'Aa']
for i in a:
if i.upper() == 'B':
val = 'found'
break
else:
val = 'not found'
print("value {}".format(val))
value found
Assuming you are looking for an exact match, you might try:
fc = 'CitiesAmtrak.shp'
field = 'NAME'
whereClause = "{} = '{}'".format(field,userInput)
if len(list(i for i in arcpy.da.SearchCursor(fc, [field],where_clause=whereClause))):
print "Found"
else:
print "Not found"
Using fuzzy might offer other options, such as "Did you mean ....".
Not addressing the equality checking issues people have raised, the else clause on the for statement was created for this type of situation:
#import necessary tools
import arcpy
from arcpy import env
import sys
#set workspace
arcpy.env.workspace = r'C:\Data' #generic source for data
#inquire user input
print "Please search for a city in New Mexico within 10 Miles of an Amtrak Station."
userInput = raw_input ("Which city would you like to check? ")
with arcpy.da.SearchCursor('CitiesAmtrak.shp', 'NAME') as citySearch:
for column in citySearch:
if userInput in column:
print "This city is within 10 miles of an Amtrak Station."
break
else:
print "no"
I would probably make a list of the cities and then check if there is an "exact" match (ignoring case) and if not see if the user input is contains by any of the names:
def main():
import arcpy
# input featureclass and field
fc = r'C:\path\to\folder\CitiesAmtrak.shp'
fld_name = 'NAME'
# create a list with uppercase names
names = [r[0].upper() for r in arcpy.da.SearchCursor(fc, (fld_name))]
user_input = (raw_input("Which city would you like to check? ")).upper()
if user_input in names:
print("City found (exact match, ignoring case)")
else:
test = [name for name in names if user_input in name]
print test
if len(test) == 1:
print("1 City found that contains with user input: {0}".format(test[0]))
elif len(test) > 1:
print("{0} Cities found that contain with user input ({1})".format(len(test), ", ".join(test)))
else:
print("No cities found...")
if __name__ == '__main__':
main()
If I test with a list of Amtrak cities:
names = [name.upper() for name in ['Albany', 'Flagstaff', 'Chicago', 'Glenwood Springs', 'Philadelphia',
'Saratoga Springs', 'New York City', 'Eugene', 'Seattle', 'Dallas', 'Albuquerque',
'Washington, DC', 'Los Angeles', 'San Antonio', 'St. Louis',
'Emeryville', 'Kansas City, MO', 'Port Huron', 'Tucson', 'Denver',
'Vancouver, BC', 'Montreal', 'New Orleans', 'Kalamazoo', 'East Lansing',
'Battle Creek', 'Boston', 'Portland', 'Tacoma']]
... and test for "new", it will print:
2 Cities found that contain with user input (NEW YORK CITY, NEW ORLEANS)
and with "York":
1 City found that contains with user input: NEW YORK CITY
and with "new york city":
City found (exact match, ignoring case)
There is something to keep in mind (apart of how to handle each case towards the user). In case you identified the city you may need the exact name to be able to do something with the result. Because,if your city is called "New York City" and the user specified "new york city" it will not match with the city you are looking for.
In order to do that you could consider creating a dictionary that holds the uppercase of the name as key and the original name as the value:
def main():
import arcpy
# input featureclass and field
fc = r'C:\path\to\folder\CitiesAmtrak.shp'
fld_name = 'NAME'
# create a list with uppercase names
dct_names = {r[0].upper(): r[0] for r in arcpy.da.SearchCursor(fc, (fld_name))}
names = dct_names.keys()
user_input = (raw_input("Which city would you like to check? ")).upper()
print user_input
if user_input in names:
print("City found (exact match, ignoring case)")
else:
test = [dct_names[name] for name in names if user_input in name]
print test
if len(test) == 1:
print("1 City found that contains with user input: {0}".format(test[0]))
elif len(test) > 1:
print("{0} Cities found that contains with user input ({1})".format(len(test), ", ".join(test)))
else:
print("No results found...")
if __name__ == '__main__':
main()