基于坐标半径筛选JSON数据的方案优化咨询
基于坐标半径筛选JSON数据的方案优化咨询
嘿,你的思路其实已经能解决问题了,但确实有可以优化的地方,咱们一步步聊:
首先先说说你当前方案的小问题:
- 你用
±0.15的经纬度范围来筛选,本质上是在选一个矩形区域,不是真正的圆形半径范围——因为经纬度的距离在不同纬度是不一样的,比如赤道上1度经度≈111km,但到高纬度会变小,所以这个矩形其实和你想的“半径”不是一回事。 - 代码里的
inRange用法可以简化,比如判断纬度是否在[userLat-0.15, userLat+0.15]之间,不用写两次正负的判断,inRange(tot.latitude, userCoordinates.latitude - 0.15, userCoordinates.latitude + 0.15)就够了,经度同理,这样逻辑更清晰。 - 用
map来遍历数组有点浪费,map是用来转换数组元素的,筛选的话用Array.filter()更语义化,不用手动push到新数组。
那优化方案分两种情况:
情况1:不需要高精度的距离计算(比如前端快速筛选)
如果只是想快速做近似筛选,保持你的思路但简化代码:
import { inRange } from 'lodash'; const filterTotems = (userCoordinates) => { const { latitude: userLat, longitude: userLng } = userCoordinates; // 直接定义范围的上下限,不用写两次判断 const filteredTot = totems.filter(tot => inRange(tot.latitude, userLat - 0.15, userLat + 0.15) && inRange(tot.longitude, userLng - 0.15, userLng + 0.15) ); setFiltredTotems(filteredTot); };
这样代码更简洁,语义也更明确。
情况2:需要真正的半径范围筛选(高精度)
如果要准确筛选出用户坐标X公里半径内的地点,就得用地理距离公式,最常用的是Haversine公式,计算两点之间的球面距离。不用依赖lodash,自己实现或者用简单的函数:
// 计算两点之间的距离(单位:公里) const calculateDistance = (lat1, lon1, lat2, lon2) => { const R = 6371; // 地球半径(公里) const dLat = (lat2 - lat1) * Math.PI / 180; const dLon = (lon2 - lon1) * Math.PI / 180; const a = Math.sin(dLat/2) * Math.sin(dLat/2) + Math.cos(lat1 * Math.PI / 180) * Math.cos(lat2 * Math.PI / 180) * Math.sin(dLon/2) * Math.sin(dLon/2); const c = 2 * Math.atan2(Math.sqrt(a), Math.sqrt(1-a)); return R * c; // 距离(公里) }; const filterTotems = (userCoordinates, radius = 10) => { // radius默认10公里 const { latitude: userLat, longitude: userLng } = userCoordinates; const filteredTot = totems.filter(tot => calculateDistance(userLat, userLng, tot.latitude, tot.longitude) <= radius ); setFiltredTotems(filteredTot); };
这个方法的优势是精准,不管用户在哪个纬度,筛选的都是真正的圆形半径范围,适合对距离精度有要求的场景。
额外小建议
- 如果你的
totems数据量很大(比如上千条),前端筛选可能会有点卡,这时候最好把筛选逻辑放到后端,用数据库的地理索引(比如PostGIS、MongoDB的地理查询),性能会好很多。 - 如果你还是想用lodash,也可以把范围判断封装成一个小函数,让代码更干净。
总的来说,你的初始方案是可行的,但根据需求选择更合适的方法会更好~
备注:内容来源于stack exchange,提问作者Jorge Fabris
相关产品推荐
相关产品推荐

