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.
-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
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.
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.
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"); } } }