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

问题描述 投票:3回答:6

我有这样的数据:

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万

  • 我想知道这是好方法,因为每天它会受到数百万人的打击
java hashmap
6个回答
1
投票

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

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

首先,创建一个包含“键”值和“值”值的类

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());

你准备好了。


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 <21.45454545 && demo.longitude> 72.3455)

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


1
投票

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

如果这对你不起作用,我会创建一个“Coordinates”类并将键存储在那里。您必须覆盖hashcode和equals方法,否则它可能不会像您希望的那样。

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
投票

HashMap不会用于你的需要,因为它不适用于范围查询,即给我一个键最接近12.0的条目,或者给我10.020.0之间的所有条目。

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

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

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


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

TreeMap<Double, TreeMap<Double, Double>> demo = new TreeMap<>();

这是TreeMapTreeMap,其想法是将纬度作为外部地图的关键,将经度作为内部地图的关键。因此,您必须首先按纬度搜索,然后按经度搜索。

如果这对你来说没问题,你可以利用一些very useful methods of TreeMap,例如headMaptailMapsubMap,来命名最相关的。

例如,如果要查找由其左上角[-10.0, -10.0]及其右下角[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);

即使是100万点,性能也是合理的,虽然不是最好的,因为TreeMap是基于红/黑树的通用Map实现,具有O(log n)时间复杂度。


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


0
投票

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


0
投票

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

© www.soinside.com 2019 - 2024. All rights reserved.