Skip to content

Instantly share code, notes, and snippets.

@hailpam
Created September 27, 2015 23:19
Show Gist options
  • Save hailpam/68a6d59445d7a6854eec to your computer and use it in GitHub Desktop.
Save hailpam/68a6d59445d7a6854eec to your computer and use it in GitHub Desktop.
Filter out Customers based on their geo-location. The output is a collection of Customers ordered by their own Id - ascending order.
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.net.URL;
import java.nio.charset.Charset;
import java.util.List;
import java.util.Objects;
import java.util.Set;
import java.util.TreeSet;
import org.json.simple.JSONObject;
import org.json.simple.parser.JSONParser;
import org.json.simple.parser.ParseException;
/**
* Filter out Customers by their own Geo-Location.
*
* @author Paolo Maresca {@email plo.maresca@gmail.com}
*/
public class GeoLocatedFiltering
{
private static final float HQ_LAT = 53.3381985f; // headquarter decimal latitude
private static final float HQ_LNG = -6.2592576f; // headquarted decimal longitude
private static final Integer EARTH_RADIUS = 6371; // expressed in Kms
private static final Integer RANGE_DISTANCE = 100; // expressed in Kms
private static final String DEFAULT_LOCATION = System.getProperty("user.dir")
+File.separator +"customers_list.txt";
private static final String DEFAULT_URL = "https://gist.githubusercontent.com/brianw/"
+ "19896c50afa89ad4dec3/raw/6c11047887a03483c50017c1d451667fd62a53ca/gistfile1.txt";
/**
* Load Customers from File.
*
* @param reader A Buffered Reader having the raw list of Customers
* @return A list of de-serialized Customers
*S
* @throws IOException
* In case of any blocking exception
* @throws ParseException
* In case of JSON Parsing Exception
*/
public static List<Customer> load(BufferedReader reader) throws IOException, ParseException
{
if(reader == null)
throw new IllegalArgumentException("Input Reader cannot be NULL");
List<Customer> customers = new LinkedList<>();
String line;
JSONParser parser = new JSONParser();
while((line = reader.readLine()) != null) {
JSONObject jsonCustomer = (JSONObject) parser.parse(line);
Customer customer = new Customer(Float.parseFloat((String) jsonCustomer.get("latitude")),
Float.parseFloat((String) jsonCustomer.get("longitude")),
(String) jsonCustomer.get("name"),
(Long) jsonCustomer.get("user_id"));
customers.add(customer);
}
return customers;
}
/**
* Select the Customers loaded from File according to the Range-based criteria.
*
* E.g. Given the HQ at (53.3381985, -6.2592576f), select the geo-located Customer in a range of
* 100 Kms.
*
* @param customers A list of Customer from which to select
* @return An ordered set
*/
public static Set<Customer> select(List<Customer> customers)
{
if(customers == null)
throw new IllegalArgumentException("Customers cannot be NULL");
Double distance = new Double(Integer.toString(RANGE_DISTANCE));
Set<Customer> ordered = new TreeSet<>();
for(Customer customer: customers) {
if(customer.howFarFrom(customer.getLatRadians(), customer.getLngRadians()) <= distance)
ordered.add(customer);
}
return ordered;
}
/**
* Main.
*
* @param args Command Line Arguments.
*/
public static void main(String[] args)
{
File jsonList = null;
BufferedReader reader = null;
if(args.length == 0)
jsonList = new File(DEFAULT_LOCATION);
else
jsonList = new File(args[0]);
List<Customer> customersList = null;
try {
if(!jsonList.exists()) {
URL jsonUrl = new URL(DEFAULT_URL);
reader = new BufferedReader(new InputStreamReader(jsonUrl.openStream(),
Charset.forName("UTF-8")));
} else
reader = new BufferedReader(new FileReader(jsonList));
customersList = load(reader);
} catch(IOException ioe) {
System.err.println("Error: Something wrong happened working with your file: [" +ioe.getMessage()+ "]");
System.exit(1);
} catch(ParseException pe) {
System.err.println("Error: Something wrong happened parsing the JSON: [" +pe.getMessage()+ "]");
System.exit(1);
} finally {
try {
reader.close();
} catch(IOException ioe) {
System.err.println("Error: Buffered Reader cannot be closed properly");
System.exit(1);
}
}
Set<Customer> filteredList = select(customersList);
for(Customer customer: filteredList)
System.out.println("Id: [" +customer.getId()+ "] - Name: [" +customer.getName()+ "]");
}
/**
* Customer POJO with a helper method to get the distance from point of interest.
*/
public static final class Customer implements Comparable<Customer>
{
private final Float lat;
private final Float lng;
private final String name;
private final Long id;
public Customer(Float lat, Float lng, String name, Long id)
{
this.lat = lat;
this.lng = lng;
this.name = name;
this.id = id;
}
@Override
public int compareTo(Customer t)
{
if(id == t.getId())
return 0;
else if(id > t.getId())
return 1;
else
return -1;
}
public Double howFarFrom(Double lat, Double lng)
{
Double latAbsDifference, lngAbsDifference, centralAngle;
latAbsDifference = Math.abs(Math.toRadians(HQ_LAT) - lat);
lngAbsDifference = Math.abs(Math.toRadians(HQ_LNG) - lng);
centralAngle = Math.acos((Math.sin(Math.toRadians(HQ_LAT)) * Math.sin(lat)) +
(Math.cos(Math.toRadians(HQ_LAT)) * Math.cos(lat) *
Math.cos(lngAbsDifference)));
return EARTH_RADIUS * centralAngle; // arc length, sperical distance
}
public Float getLat() { return lat; }
public Float getLng() { return lng; }
public Double getLatRadians() { return Math.toRadians(lat); }
public Double getLngRadians() { return Math.toRadians(lng); }
public String getName() { return name; }
public Long getId() { return id; }
@Override
public int hashCode()
{
int hash = 7;
hash = 53 * hash + Float.floatToIntBits(this.lat);
hash = 53 * hash + Float.floatToIntBits(this.lng);
hash = 53 * hash + Objects.hashCode(this.name);
hash = 53 * hash + Objects.hashCode(this.id);
return hash;
}
@Override
public boolean equals(Object obj)
{
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Customer other = (Customer) obj;
if (Float.floatToIntBits(this.lat) != Float.floatToIntBits(other.lat)) {
return false;
}
if (Float.floatToIntBits(this.lng) != Float.floatToIntBits(other.lng)) {
return false;
}
if (!Objects.equals(this.name, other.name)) {
return false;
}
if (!Objects.equals(this.id, other.id)) {
return false;
}
return true;
}
@Override
public String toString()
{
return "Customer { " + "lat=" + lat + ", lng=" + lng + ", name=" + name + ", id=" + id + " }";
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment