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.
+3


source to share


6 answers


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.

+1


source


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.

+2


source


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.*/

      

+1


source


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.

+1


source


You can generate a hashcode based on longitude, latitude, and then use that hashcode as a key to store your values. This way it will be easier, instead of using them directly or converting them to a point, as there is no point in using a point at a later point in time.

0


source


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)

0


source







All Articles