Make longitude and latitude as Key of HashMap in Java
I have data like this:
23.3445556 72.4535455 0.23434
23.3645556 72.4235455 0.53434
23.3245556 72.4635455 0.21434
23.3645556 72.2535455 0.25434
I want to do HashMap
like this:
HashMap<23.34444,72.23455,0.2345566> demo = new HashMap()
Here 23.34444,72.23455
is the key and 0.2345566
is the value.
This is because I want to go through HashMap
like this:
if(demo.latitude < 21.45454545 && demo.longitude > 72.3455)
//get the value from hashMap
long lat repn a specific pixel on the map, every pixel has the same value, I want to get the average from a specific area, suppose xy and pixel will be up to 1 million
- And I want to know if this is a good thing, because every day he will receive millions.
source to share
I think you are approaching the problem in the wrong way. Usage HashMap
will not work correctly with larger or smaller comparisons. What happens if you had 2 Latlong keys that matched your comparison? Which value will you choose?
I would probably solve your problem like this:
First, create a class that will contain both your "key" values ββand your "value"
public class GeoValue {
double lat;
double lon;
double value;
}
Then add a comparison method to the class
public boolean lessThanLatGreaterThanLon(double lat, double lon) {
return lat < this.lat && lon > this.lon;
}
Add all created objects to the collection of types Set
. If you are using HashSet
, make sure you also override the method .equals()
and .hashCode
for your class GeoValue
.
To find the values ββyou want you can use the method filter
(if you are in Java8 or example)
final double lat = 3.5D;
final double lon = 4.5D;
Set<GeoValue> matchingValues = geoValues.stream()
.filter(geo -> geo.lessThanLatGreaterThanLon(lat, lon))
.collect(Collectors.toSet());
And you're ready to go.
source to share
You can use the Point class to start with.
https://docs.oracle.com/javase/7/docs/api/java/awt/Point.html
int xE6 = x*1e6
int yE6 = y*1e6
new Point(xE6, yE6)
But since this is specific and misuses the class, you will probably want to create your own eventually.
public final class LatLon {
private double lat;
private double lon;
public LatLon(double lat, double lon) {
this.lat = lat;
this.lon = lon;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
LatLon latLon = (LatLon) o;
if (Double.compare(latLon.lat, lat) != 0) return false;
return Double.compare(latLon.lon, lon) == 0;
}
@Override
public int hashCode() {
int result;
long temp;
temp = Double.doubleToLongBits(lat);
result = (int) (temp ^ (temp >>> 32));
temp = Double.doubleToLongBits(lon);
result = 31 * result + (int) (temp ^ (temp >>> 32));
return result;
}
public double getLat() {
return lat;
}
public void setLat(double lat) {
this.lat = lat;
}
public double getLon() {
return lon;
}
public void setLon(double lon) {
this.lon = lon;
}
}
(autogenerated using IntelliJ)
This can be used like
public static void main(String[] args) {
HashMap<LatLon, Double> demo = new HashMap<LatLon, Double>();
demo.put(new LatLon(23.3445556,72.4535455), 0.23434);
demo.put(new LatLon(23.3645556,72.4235455), 0.53434);
demo.put(new LatLon(23.3245556,72.4635455), 0.21434);
demo.put(new LatLon(23.3645556,72.2535455), 0.25434);
System.out.println(demo.get(new LatLon(23.3645556,72.2535455))); //0.25434
}
The problem with using this class as is is that it uses doubles. You need some kind of precision given by the decimal point.
doubles up on weird math and can give you precision errors, so I heartily recommend using a geo-coordinating library.
Highly recommended
if (demo.latitude <21.45454545 & demo.longitude> 72.3455)
This kind of validation is best served by some kind of specially crafted collection to handle bounds and coordinates checks if you run into performance issues.
source to share
If this is a demo you are creating, I would suggest creating an enum class with each coordinate you want to demonstrate as a separate enumeration object or as a key to a HashMap.
If that doesn't work for you, I would create a Coordinates class and store the keys there. You will have to override the hashcode and equals method, although it may not behave the way you want.
Example
public class Coordinates {
double latitude, longitude;
}
...
HashMap<Coordinates, Double> demo = new HashMap<>(); /* Note: An object of Coordinates is the key. So, you first have to make an object of Coordinates class, put the latitude and longitude values and then put in the HashMap as key.*/
source to share
HashMap
won't be useful for your needs because it is not designed for range queries, i.e. give me the entry whose key is closest to 12.0
, or give me all entries between the keys 10.0
and 20.0
.
There are special structures that effectively work with geo-points, i.e. R-tree or R * tree .
These trees require you to index your data based on a geo-point, such as structures, usually latitude / longitude pairs, although they also allow you to index data based on geo-shapes.
Making a lat / lon pair object to use as a key (as suggested in other answers) is only useful if you are using a specialized framework that stores and indexes spatial data. Otherwise, the pair will be meaningless, because you won't be able to search for points that are near the given location, or points that lie within a given rectangle, etc.
Now, if you don't want to walk the R-tree, and you can live with fairly limited spatial queries, you may need to use the following structure:
TreeMap<Double, TreeMap<Double, Double>> demo = new TreeMap<>();
It is TreeMap
of TreeMap
s and the idea is for latitude to be the key of the outer map and longitude as the key of the inner maps. Therefore, you will always have to search first by latitude, then by longitude .
If that works for you, you can use some very useful methodsTreeMap
such as headMap
, tailMap
and subMap
to name the most relevant ones.
For example, if you want to find all the points in a rectangle defined by its upper-left corner [-10.0, -10.0]
and its lower-right corner [10.0, 10.0]
, you can do it like this:
// Get all points with latitude between -10.0 and 10.0
SortedMap<Double, TreeMap<Double, Double>> byLat = demo.subMap(-10.0, 10.0);
// Now print points from byLat submap with longitude between -10.0 and 10.0
byLat.entrySet().stream()
.map(e -> e.getValue().subMap(-10.0, 10.0))
.forEach(System.out::println);
Even for 1 million points, the performance will be reasonable, although not the best, since it TreeMap
is a general purpose Map
Red / Black tree based implementation that has O(log n)
time complexity.
On the other hand, if you want to install any software, I recommend using Elasticsearch with Geolocation . It has geo-point and geo-shaped specialized which will make your life easier. This search engine has excellent performance and scales horizontally to thousands of nodes, hence memory, search time, etc. Will not be a problem.
source to share
You can also use the Point2D class available as part of the java.awt. You will need to extend it and create a concrete class, but it will give you equals / hashcode, etc. All built-in. For integer coordinates, you can just use the Point class from the same library (no need to extend either)
source to share