有没有更有效的编码方法?
有问题的代码是第二个 foreach 循环中包含的代码,其目的是防止精确重复的纬度和经度。
foreach($aUsers as $k => $v)
{
// generate address
$aAddress = array();
if(!empty($v['city_location']))
$aAddress[] = $v['city_location'];
if(!empty($v['country_child_id']))
{
$aRow = $oDb->select('name')
->from(getT('country_child'))
->where('child_id = \''.$v['country_child_id'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
if(!empty($v['postal_code']))
$aAddress[] = $v['postal_code'];
if(!empty($v['country_iso']))
{
$aRow = $oDb->select('name')
->from(getT('country'))
->where('country_iso = \''.$v['country_iso'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
$sAddress = implode(', ',$aAddress);
/// get location
$aLatLon = $oGeoMap->getLatLon($v['user_id'],1,$sAddress);
if($aLatLon['success'] === true)
{
foreach($aUsers as $k2 => $v2)
{
$iAdd = .01;
$iAttempts = 0;
while($v2['latitude'] == $aLatLon['latitude'] && $v2['longitude'] == $aLatLon['longitude'])
{
$iAttempts++;
switch($iAttempts){
case 1:
$aLatLon['latitude'] += $iAdd;
break;
case 2:
$aLatLon['longitude'] += $iAdd;
break;
case 3:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 4:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 5:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 6:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 7:
$iAdd += .01;
$iAttempts = 0;
break;
}
}
}
$aUsers[$k]['latitude'] = $aLatLon['latitude'];
$aUsers[$k]['longitude'] = $aLatLon['longitude'];
$aUsers[$k]['address'] = $sAddress;
}
else
unset($aUsers[$k]);
}
The code in question is the code contained within the 2nd foreach loop, the purpose of which is to prevent exact duplicate latitude and longitudes.
foreach($aUsers as $k => $v)
{
// generate address
$aAddress = array();
if(!empty($v['city_location']))
$aAddress[] = $v['city_location'];
if(!empty($v['country_child_id']))
{
$aRow = $oDb->select('name')
->from(getT('country_child'))
->where('child_id = \''.$v['country_child_id'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
if(!empty($v['postal_code']))
$aAddress[] = $v['postal_code'];
if(!empty($v['country_iso']))
{
$aRow = $oDb->select('name')
->from(getT('country'))
->where('country_iso = \''.$v['country_iso'].'\'')
->execute('getRow');
$aAddress[] = $aRow['name'];
}
$sAddress = implode(', ',$aAddress);
/// get location
$aLatLon = $oGeoMap->getLatLon($v['user_id'],1,$sAddress);
if($aLatLon['success'] === true)
{
foreach($aUsers as $k2 => $v2)
{
$iAdd = .01;
$iAttempts = 0;
while($v2['latitude'] == $aLatLon['latitude'] && $v2['longitude'] == $aLatLon['longitude'])
{
$iAttempts++;
switch($iAttempts){
case 1:
$aLatLon['latitude'] += $iAdd;
break;
case 2:
$aLatLon['longitude'] += $iAdd;
break;
case 3:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 4:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 5:
$aLatLon['latitude'] += $iAdd;
$aLatLon['longitude'] -= $iAdd;
break;
case 6:
$aLatLon['latitude'] -= $iAdd;
$aLatLon['longitude'] += $iAdd;
break;
case 7:
$iAdd += .01;
$iAttempts = 0;
break;
}
}
}
$aUsers[$k]['latitude'] = $aLatLon['latitude'];
$aUsers[$k]['longitude'] = $aLatLon['longitude'];
$aUsers[$k]['address'] = $sAddress;
}
else
unset($aUsers[$k]);
}
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
我强烈同意弗兰克·法默的评论,但如果您坚持这种做事方式,请尝试按照以下方式进行操作:
也就是说,如果我正确理解您的意图。并更改变量名称以符合您自己的标准;-)
代码未经测试。
不,我不会重新阅读完整的代码;-)
I strongly agree with Frank Farmer's comment, but if you insist on this way of doing things try something along these lines:
That is, if I understand your intention correctly. And change variable names to adhere to your standards yourself ;-)
Code is untested.
And no, I'm not going to re-read the full code ;-)
您可以尝试使用第二种数据结构来保存现有的纬度+经度位置,例如按纬度然后经度索引的二维用户数组。您无需循环遍历
$aUsers
数组,而是检查另一个数据结构中是否存在给定的纬度和经度。请注意,由于您只能使用整数和字符串作为数组键,并且将浮点数转换为整数或字符串将导致精度损失,因此如果您使用纬度和,则应将浮点数转换为其位字符串等效项经度作为键。一个简单的
pack('d', $l)
应该可以工作,或者您可以使用:如果您知道您的纬度和经度存储为浮点数而不是双精度数(尽管我相当确定 PHP 只使用双打),您可以使用“f”作为包格式而不是“d”。
为了提高可读性,您可以将部分代码(例如
switch($iAttempts)
)重构为附加函数。至于多人在一个位置的问题,另一种解决方案(假设地图显示在屏幕上,而不是打印出来)是为一组人使用不同的指示器。当用户将鼠标悬停在组图标上时,它可以“爆炸”成星形的单个图标(如果有意义的话),每个图标都有一条线将图标连接到人员的位置。我在几个应用程序中看到过类似的内容,但现在无法想到是哪些。
You could try using a second data structure that holds existing latitude+longitude positions, e.g. a 2-D array of users indexed by latitude then longitude. Rather than looping over the
$aUsers
array, you check whether a given latitude and longitude exists within this other data structure.Note that as you can only use integers and strings as array keys and casting floating point numbers to either integers or strings will result in a loss of precision, you should convert floating point numbers to their bit-string equivalents if you're using latitude and longitude as keys. A simple
pack('d', $l)
should work, or you could use:If you know your latitude and longitude are stored as floats and not doubles (though I'm fairly certain PHP only uses doubles), you can use 'f' as the pack format rather than 'd'.
For readability, you can refactor parts of the code (e.g. the
switch($iAttempts)
) as additional functions.As for the problem of multiple people at a single location, another solution (assuming the map is displayed on a screen, rather than printed) is to use a different indicator for a group of people. When a user mouses over the group icon, it can "explode" into a star of individual icons (if that makes sense), each with a line connecting the icon to the people's location. I've seen something similar in a couple applications, but can't think which ones right now.
您可以使用带有分号的 switch() ...例如还
没有测试过这个;但我确信如果你继续这样做或类似的事情,它会起作用。
希望这有帮助
You could use switch() with a semicolon... E.g.
Haven't tested this; but I'm sure if you keep going like this or something similar, it will work.
Hopefully that helped
建议:
这更多的是对所有代码的一般建议,而不仅仅是内部循环。我会更改代码以使用专用结构而不是数组。这是一个基本示例:
实际答案:
就优化内部循环而言,我只需删除该代码。要么提出一个新的 UI 元素,让多个用户位于同一位置,要么忽略用户(如果他们的纬度/经度已添加到地图中)。
如果你必须保留它,迈克尔的解决方案看起来不错。
Suggestion:
This is more of a general suggestion for all the code, not just the inner loop. I would change the code to use dedicated structures instead of arrays. Here's a basic example:
Actual answer:
As far as optimizing the inner loop, I would just delete that code. Either come up with a new UI element for having multiple users in the same location, or ignore a user if their lat/long has already been added to the map.
If you must keep it, Michael's solution looked good.