Store Locator using Java
We would like to write a program to find the closest store to an input address. The program is provided with a list of locations; it asks for an input address, and then outputs the closet store location.
The dataset here contains geographical locations of McDonald’s in North America. It is a CSV (Comma-Separated Values) file with three columns: latitude, longitude, and address.
1 2 3 4 | -122.994495, 49.281079, 4805 E Hastings St Burnaby BC V5C 2L1 -123.029985, 49.281001, 3444 E Hastings Street Vancouver BC V5K 2A6 -123.024074, 49.265642, 3695 Lougheed Hwy Vancouver BC V5M 2A6 ...... |
Solution
The basic idea is as below:
- Design a Store class, and load all data into an ArrayList of Stores.
- Ask the user for an address, and find its geographical location.
- Scan through the ArrayList of all stores to find the closest one.
First, we define the Location class with the following attributes and methods:
- String address
- double latitude
- double longitude
- public Location(String addr, double lat, double lng)
- double distanceTo(Location loc): computes the distance to loc
- String toString(): displays the location
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 | public class Location { private String address; private double latitude; private double longitude; public Location(String addr, double lat, double lng) { address = addr; latitude = lat; longitude = lng; } // Compute the distance in meters public double distanceTo(Location loc) { double earthRadius = 3958.75 ; double dLat = Math.toRadians(latitude - loc.latitude); double dLng = Math.toRadians(longitude - loc.longitude); double a = Math.sin(dLat/ 2 ) * Math.sin(dLat/ 2 ) + Math.cos(Math.toRadians(latitude)) * Math.cos(Math.toRadians(latitude)) * Math.sin(dLng/ 2 ) * Math.sin(dLng/ 2 ); double c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt( 1 -a)); double dist = earthRadius * c; return dist * 1609 ; } public String toString() { return address + " (" + latitude + ", " + longitude + ")"; } } |
Now we define a tool class LocationTool. It has the following methods:
- ArrayList loadData(String urlString): reads data from the url
- Location makeLocation(String addr): creates a location object from an address. We use Google’s geocoding services to find the latitude and longitude of an address string.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 | import java.io.IOException; import java.net.URL; import java.net.URLEncoder; import java.util.Scanner; public class LocationTool { // Read from URL and return the content in a String public static String readURLContent(String urlString) throws IOException { URL url = new URL(urlString); Scanner scan = new Scanner(url.openStream()); String content = new String(); while (scan.hasNext()) content += scan.nextLine(); scan.close(); return content; } // Extract the middle part of a string from "open" to "close" public static String extractMiddle(String str, String open, String close) { int begin = str.indexOf(open) + open.length(); int end = str.indexOf(close, begin); return str.substring(begin, end); } // Extract the middle part of a string from "open" to the end public static String extractMiddle(String str, String open) { int begin = str.indexOf(open) + open.length(); return str.substring(begin); } // Make a Location object from a string address public static Location makeLocation(String addr) throws IOException { String url = "http: //maps.google.com/maps/api/geocode/json?sensor=false&address="; url += URLEncoder.encode(addr, "UTF- 8 "); String content = readURLContent(url); String formatted_address = extractMiddle(content, "\"formatted_address\" : \"", "\","); String latlng = extractMiddle(content, "\"location\" : {", "},"); double lat = Double.parseDouble(extractMiddle(latlng, "\"lat\" :", ",")); double lng = Double.parseDouble(extractMiddle(latlng, "\"lng\" :")); return new Location(formatted_address, lat, lng); } } |
Finally we build the main program Locator with a main method. As the program starts, it loads the data; then it asks for an input address, finds its geographical location, and searches for the closet store.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 | import java.io.IOException; import java.util.ArrayList; import java.util.Scanner; public class Locator { public static void main(String[] args) throws IOException { String urlStr = "http: //www.theoryapp.com/wp-content/uploads/2013/01/mcdonalds.csv"; ArrayList<Location> stores = LocationTool.loadData(urlStr); Scanner scan = new Scanner(System.in); while ( true ) { System.out.println("Please type in an address:"); String addr = scan.nextLine(); if (addr.length() == 0 ) break ; Location loc = LocationTool.makeLocation(addr); System.out.println("Your location is at: " + loc); double distance = - 1 ; Location nearStore = null ; for (Location e : stores) { double d = loc.distanceTo(e); if (d <= distance || distance < 0 ) { distance = d; nearStore = e; } } System.out.println("The closet McDonald is at: " + nearStore); System.out.println("The distance is " + ( int ) distance + " m"); } } } |