2017-06-13 69 views
3

我有这样的数据:使经度和纬度的HashMap的重点在Java中

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 

在地图上长纬度repn特定像素,每个像素具有相同的价值,我想从特定区域假设XY和像素平均价值将高达百万

  • ,我想知道这是否是很好的方法,因为它每天将获得数百万打
+2

把这个:*** 23.34444,72.23455 ***变成一个点类 –

+1

听起来像你想要一个类代表经纬度值... –

+0

看到https://stackoverflow.com/questions/30125954/storing-longitude-纬度值 – user7294900

回答

1

我认为你是以错误的方式接近问题。使用HashMap在比较大于或小于比较时无法正常工作。如果您有两个与您的比较匹配的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,请确保您也覆盖GeoValue类的.equals().hashCode方法。

要找到你想要的,你可以使用一个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()); 

值,你准备好去。

1

如果它是一个你正在创建的演示,我会建议创建一个枚举类,每个坐标你想展示为一个单独的枚举对象或作为HashMap的关键。

如果这不适合你,我会创建一个“坐标”类并将密钥存储在那里。你将不得不重写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.*/ 
+3

该类不完整以用于HashMap – AxelH

+0

您是什么意思“class is incomplete “? –

+1

他意味着你还需要有一个'hashCode'方法才能使类正确地工作为'HashMap'键 – Konstantine

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) 

但由于这是AWT具体类的误用,你可能最终想要创建自己的。

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 
} 

使用的问题原样使用这个类,是它使用双打。你想要一些精确度,由小数点位置给出。

双打有奇怪的数学,并可以给你准确性的错误,所以我衷心推荐使用专为地理坐标设计的图书馆。

特别是考虑

如果(demo.latitude < 21.45454545 & & demo.longitude> 72.3455)

这类检查最好是通过某种特定目的建造收集用于处理服务如果你最终遇到了性能问题,则可以进行边界检查和协调。

+0

AWT点用于表示屏幕上的坐标,以像素为单位。因此,坐标是'int',而不是lat/long所需要的'double'。另外,'x * 10^6'可能不会做你认为它做的事情。 –

+0

我把它改成了两倍,主要是因为我懒得创建一个基于Int的答案,这个答案可以转换为intE6位置格式,并且可以转换为这个问题。 –

0

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

+0

你假设你以后不需要它们。既然它在条件中使用了两个值,我将使用一个实例来代替这样的生成哈希码。 – AxelH

+0

这比在'hashcode'方法中使用相同逻辑的'Point'类更简单吗?直接使用哈希码,不可能将地图上的按键转换回坐标。 –

1

HashMap不会使用您的需求的,因为它不是为范围查询,即给我其主要是最接近12.0进入,或者给我钥匙10.020.0之间的所有条目。

有一些特殊用途的结构可以有效地处理地理点,例如R-treeR* tree

这些类型的树需要基于类似地理位置的结构(通常是纬度/经度对)对数据建立索引,尽管它们也允许基于地理形状对数据进行索引。

仅当您使用存储和索引空间数据的专用结构时,创建经纬度对对象才能用作关键字(如其他答案中的建议)。否则,有这样一对将是毫无意义的,因为你将无法搜索是附近给定的位置躺下一个给定的矩形内的点,或者点等,现在


,如果你不想去的R-树的方式,你可以用相当有限的空间查询生活,你可能要考虑使用以下结构:

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

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

如果这是给你的好,你可以利用一些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

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