将经度和纬度作为Java中HashMap的键

时间:2017-06-13 07:45:59

标签: java hashmap

我有这样的数据:

23.3445556 72.4535455 0.23434
23.3645556 72.4235455 0.53434
23.3245556 72.4635455 0.21434
23.3645556 72.2535455 0.25434

我想这样HashMap

HashMap<23.34444,72.23455,0.2345566> demo = new HashMap()

此处23.34444,72.23455是关键,0.2345566是值。

这是因为我想像这样遍历HashMap

if(demo.latitude < 21.45454545 && demo.longitude > 72.3455)
    //get the value from hashMap   

long lat repn在地图上的特定像素,每个像素都有相同的值,我想从特定区域获得avg值假设x y和像素将高达100万

  • 我想知道这是好方法,因为每天会有数百万人受欢迎

6 个答案:

答案 0 :(得分:2)

您可以使用Point类开始。

https://docs.oracle.com/javase/7/docs/api/java/awt/Point.html

int xE6 = x*1e6
int yE6 = y*1e6
new Point(xE6, yE6)

但由于这是特定的,并且滥用了这个课程,你最终可能会想要创建自己的课程。

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;
    }
}

(使用IntelliJ自动生成)

这可以像

一样使用
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
}

使用此类的问题在于它使用了双精度型。您需要某种精度,由小数位置给出。

双打有奇怪的数学,并且可以给你准确性错误,所以我衷心建议使用专为地理坐标设计的库。

特别是

  

if(demo.latitude&lt; 21.45454545&amp;&amp; demo.longitude&gt; 72.3455)

如果最终遇到性能问题,这种检查最好通过某种专门构建的集合来处理边界检查和坐标。

答案 1 :(得分:1)

如果它是您正在创建的演示,我建议您创建一个枚举类,其中每个坐标都要展示为单独的枚举对象或HashMap的键。

如果这不适合你,我会创建一个&#34; Coordinates&#34;在那里分类并存储密钥。你必须覆盖hashcode和equals方法,否则它可能不会像你想要的那样。

  

实施例

step. 5

答案 2 :(得分:1)

我认为你正在以错误的方式解决问题。使用HashMap将无法正常使用大于或小于比较。如果您有2个与您的比较匹配的latlong键,会发生什么?你选择什么价值?

我可能会像这样解决你的问题:

首先,创建一个包含&#34;键&#34;的类。价值和你的价值&#34;值

public class GeoValue {
  double lat;
  double lon;
  double value;
}

然后,将比较方法添加到类

public boolean lessThanLatGreaterThanLon(double lat, double lon) {
  return lat < this.lat && lon > this.lon;
}

将所有这些创建的对象添加到Set类型集合中。如果您使用HashSet,请确保同时覆盖.equals()课程的.hashCodeGeoValue方法。

要查找所需的值,您可以使用filter方法(如果您使用的是Java8或示例)

final double lat = 3.5D;
final double lon = 4.5D;
Set<GeoValue> matchingValues = geoValues.stream()
    .filter(geo -> geo.lessThanLatGreaterThanLon(lat, lon))
    .collect(Collectors.toSet());

你准备好了。

答案 3 :(得分:1)

HashMap将无法满足您的需求,因为它不适用于范围查询,即为我提供其密钥最接近12.0的条目,或者为我提供密钥之间的所有条目{ {1}}和10.0

有效地处理地理点的特殊用途结构,即R-treeR* tree

这类树需要您根据类似地理位置的结构(通常是纬度/经度对)索引数据,但它们也允许根据地理形状对数据进行索引。

创建要用作键的lat / lon对对象(如其他答案中所建议)仅在使用存储空间数据并将其编入索引的专用结构时才有用。否则,具有此类对将是毫无意义的,因为您将无法搜索附近给定位置的点,或位于给定矩形内的点等。

现在,如果您不想使用R-tree的方式,并且可以使用非常有限的空间查询,则可能需要考虑使用以下结构:

20.0

这是TreeMap<Double, TreeMap<Double, Double>> demo = new TreeMap<>(); 的{​​{1}},其目的是将纬度作为外部地图的关键,将经度作为内部地图的关键。 因此,您必须首先按纬度搜索,然后按经度搜索

如果你没问题,你可以利用一些very useful methods of TreeMap,例如TreeMapTreeMapheadMap,来命名最相关的。{ / p>

例如,如果要查找由其左上角tailMap及其右下角subMap确定的矩形内的所有点,可以按以下方式执行:

[-10.0, -10.0]

即使是100万分,性能也是合理的,但不是最好的,因为[10.0, 10.0]是基于红/黑树的通用// 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); 实现,TreeMap时间复杂度。

另一方面,如果您愿意安装某些软件,我建议您将ElasticsearchGeolocation一起使用。它具有geo-pointgeo-shaped专用数据类型,可以让您的生活更轻松。这个搜索引擎具有出色的性能,可以水平扩展到数千个节点,因此内存,查找时间等都不会成为问题。

答案 4 :(得分:0)

您可以根据经度,纬度生成哈希码,然后使用该哈希码作为保存值的键。这样它将更简单,而不是直接使用它们或将它们转换为一个点,因为在以后的某个时间点没有使用该点。

答案 5 :(得分:0)

您还可以使用Point2D类作为java.awt的一部分。你将需要扩展它并制作一个具体的类,但它会给你所有内置的equals / hashcode等。对于整数坐标,你可以使用相同库中的Point类(不需要扩展)