核心思想:
1.以当前登录用户为中心,向四个方向获取最近用户
2.汇总查询出的用户,计算当前用户与这些用户的精确距离
3.按最短距离排序
图例:
数据表sql:
CREATE TABLE IF NOT EXISTS `location` (
`id` int(11) NOT NULL AUTO_INCREMENT,
`x` decimal(10,0) NOT NULL,
`y` decimal(10,0) NOT NULL,
`user` varchar(200) NOT NULL,
PRIMARY KEY (`id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8 AUTO_INCREMENT=1 ;
程序1:创建n个用户
<?php
$values = array();
for ($i=0; $i<500; $i++)
{
$x = rand(1, 1000);
$y = rand(1, 1000);
$values [] = "({$x}, {$y}, 'user_{$i}')" ;
}
$sql = 'insert into location(`x`, `y`, `user`) values'.implode(',', $values) ;
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'lixinxin') ;
$db->query('set names utf8');
$flag = $db->exec($sql);
if($flag > 0){
printf("insert ok \n");
}
?>
程序2:获取附近的人
<?php
/**
* 获取附近的人(8名)
*/
$my_x = 200;
$my_y = 100;
$ulist = array();
$limit = 8;
$db = new PDO('mysql:host=localhost;dbname=test', 'root', 'lixinxin') ;
$db->query('set names utf8');
$sqls[] = "select * from location where x>$my_x and y>$my_y order by x asc,y asc limit 8" ; //右上方向 x++ y++
$sqls[] = "select * from location where x>$my_x and y<$my_y order by x asc,y desc limit 8" ; //右下方向 x++ y--
$sqls[] = "select * from location where x<$my_x and y>$my_y order by x desc,y asc limit 8" ; //左上方向 x-- y++
$sqls[] = "select * from location where x<$my_x and y<$my_y order by x desc,y desc limit 8" ; //左下方向 x-- y--
foreach ($sqls as $sql)
{
$query = $db->query($sql);
if ($query)
{
$data = $query->fetchAll(PDO::FETCH_ASSOC);
if (is_array($data)){
$ulist = array_merge($ulist, $data);
}
}
}
foreach ($ulist as $_key => $_val)
{
$ulist[$_key]['distance'] = getDistance($my_x, $my_y, $_val['x'], $_val['y']);
}
usort($ulist, function($m, $n){
if ($m['distance'] == $n['distance']) return 0;
if ($m['distance'] > $n['distance']) return 1;
return -1;
}) ;
$ulist = array_splice($ulist, 0, 8); // limit 8
file_put_contents('./log.txt', var_export($ulist, true)); // debug
function getDistance($x1, $y1, $x2, $y2)
{
$line_a = abs($x1-$x2);
$line_b = abs($y1-$y2);
// C^2 = A^2 + B^2
$line_c = pow(pow($line_a, 2) + pow($line_b, 2), 1/2);
return intval($line_c);
}
?>