我目前正在创建一个由mysql查询中的值组成的排序方法。
以下是该数组的简要视图:
Array
(
[0] => Array
(
['id'] = 1;
['countries'] = 'EN,CH,SP';
)
[1] => Array
(
['id'] = 2;
['countries'] = 'GE,SP,SV';
)
)
我已经成功地根据数字id值进行了正常的操作,但是我更愿意按照“countries”字段的内容对数组进行排序(如果它包含一个设置字符串,在这种情况下是一个国家/地区代码) ,然后是id字段。
以下片段是我第一次想到如何做到这一点,但我不知道如何将其纳入工作函数:
in_array('EN', explode(",",$a['countries']) );
你会怎么做?
谢谢!
不幸的是,我真的无处可去。
这是我目前所拥有的,它只给我一些错误:uasort() [function.uasort]: Invalid comparison function
function compare($a, $b) {
global $usercountry;
if ( in_array($usercountry, $a['countries']) && in_array($usercountry, $a['countries']) ) {
$return = 0;
}
else if (in_array($usercountry, $a['countries'])) {
$return = 1;
}
else {
$return = -1;
}
return $return;
}
$array= usort($array, "compare");
是否有人可能会给我一些如何继续使用它的提示?
答案 0 :(得分:12)
就个人而言,我会将自定义(匿名)功能与usort()
结合使用。
编辑:重新 - 您的评论。希望这会让你走上正轨。此功能同样优先考虑既具有EN又不具有EN的元素,或仅在具有EN的情况下调整优先级。
usort($array,function ($a, $b) {
$ac = strpos($a['countries'],'EN');
$bc = strpos($b['countries'],'EN');
if (($ac !== false && $bc !== false) || ($ac == false && $bc == false)) {
return 0;
}
elseif ($ac !== false) {
return 1;
}
else {
return -1;
}
});
另一方面,如果两个都有EN,则此函数给予相同的优先级,如果一个有EN,则给予相同的优先级;如果两者都没有EN,则执行文本比较。
usort($array,function ($a, $b) {
$ac = strpos($a['countries'],'EN');
$bc = strpos($b['countries'],'EN');
if ($ac !== false && $bc !== false)) {
return 0;
}
elseif ($ac !== false) {
return 1;
}
elseif ($bc !== false) {
return -1;
}
else {
if ($a['countries'] == $b['countries']) {
return 0;
}
elseif($a['countries'] > $b['countries']) {
return 1;
}
else {
return -1;
}
}
});
再次,希望这会给你足够的方向来自己前进。如果您遇到任何问题,请随时发表更多评论,我会尽力提供帮助。 如果您想将多个属性与重量进行比较,请注意:尝试一个时髦的开关块,例如
$ac = array_flip(explode(',',$a['countries']));
$bc = array_flip(explode(',',$b['countries']));
switch (true) {
case array_key_exists('EN',$ac) && !array_key_exists('EN',$bc):
return 1;
case array_key_exists('DE',$ac) && !array_key_exists('EN',$bc) && !array_key_exists('EN',$bc):
return 1;
// and so on
}
实际上,我正在考虑更复杂的排序问题,我已经提出了以下解决方案供您考虑。它允许您根据将出现在国家/地区索引中的关键字来定义数字排名。这是代码,包括一个例子:
示例数组
$array = array(
array(
'countries' => 'EN,DE,SP',
),
array(
'countries' => 'EN,CH,SP',
),
array(
'countries' => 'DE,SP,CH',
),
array(
'countries' => 'DE,SV,SP',
),
array(
'countries' => 'EN,SP,FR',
),
array(
'countries' => 'DE,FR,CH',
),
array(
'countries' => 'CH,EN,SP',
),
);
排序常规
$rankings = array(
'EN' => 10,
'SP' => 8,
'FR' => 7,
'DE' => 5,
'CH' => 3,
'SV' => 1,
);
usort($array, function (&$a, &$b) use ($rankings) {
if (isset($a['_score'])) {
$aScore = $a['_score'];
}
else {
$aScore = 0;
$aCountries = explode(',',$a['countries']);
foreach ($aCountries as $country) {
if (isset($rankings[$country])) {
$aScore += $rankings[$country];
}
}
$a['_score'] = $aScore;
}
if (isset($b['_score'])) {
$bScore = $b['_score'];
}
else {
$bScore = 0;
$bCountries = explode(',',$b['countries']);
foreach ($bCountries as $country) {
if (isset($rankings[$country])) {
$bScore += $rankings[$country];
}
}
$b['_score'] = $bScore;
}
if ($aScore == $bScore) {
return 0;
}
elseif ($aScore > $bScore) {
return -1;
}
else {
return 1;
}
});
注意:此代码会将排名最高的entires排序到数组顶部。如果您想要反向行为,请更改此:
elseif ($aScore > $bScore) {
到
elseif ($aScore < $bScore) {
请注意,大于号已更改为小于号。进行此更改将导致排名最低的条目排序到数组顶部。希望这一切都有帮助!
此代码将对您的数组进行一些小改动,因为它会将_score元素添加到每个数组中。希望这不是一个问题,因为通过存储这个值,我实际上能够将速度提高一倍以上(在我的基准测试中,.00038-.00041降至.00016-.00018)。如果没有,删除检索缓存值的if
块,并且每次都执行else
块的内容,当然除了存储得分值的部分。
顺便说一句,这是数组排序后的var_export()
转储:
array (
0 => array (
'countries' => 'EN,SP,FR',
'_score' => 25,
),
1 => array (
'countries' => 'EN,DE,SP',
'_score' => 23,
),
2 => array (
'countries' => 'EN,CH,SP',
'_score' => 21,
),
3 => array (
'countries' => 'CH,EN,SP',
'_score' => 21,
),
4 => array (
'countries' => 'DE,SP,CH',
'_score' => 16,
),
5 => array (
'countries' => 'DE,FR,CH',
'_score' => 15,
),
6 => array (
'countries' => 'DE,SV,SP',
'_score' => 14,
),
)
享受!
答案 1 :(得分:2)
终于在PHP.net上找到了这个奇妙的功能:
function array_msort($array, $cols)
{
$colarr = array();
foreach ($cols as $col => $order) {
$colarr[$col] = array();
foreach ($array as $k => $row) { $colarr[$col]['_'.$k] = strtolower($row[$col]); }
}
$eval = 'array_multisort(';
foreach ($cols as $col => $order) {
$eval .= '$colarr[\''.$col.'\'],'.$order.',';
}
$eval = substr($eval,0,-1).');';
eval($eval);
$ret = array();
foreach ($colarr as $col => $arr) {
foreach ($arr as $k => $v) {
$k = substr($k,1);
if (!isset($ret[$k])) $ret[$k] = $array[$k];
$ret[$k][$col] = $array[$k][$col];
}
}
return $ret;
}
这是每个国家的样子: $ array ['countries'] = in_array($ needle,$ haystack); }
$array = $array = array_msort($array, array('countries'=>SORT_DESC, 'id'=>SORT_ASC));
感谢大家的帮助!
答案 2 :(得分:1)
您可以考虑array_walk
和array_walk_recursive
以及array_map
,这些内容组合在一起可能会让您做您想做的事情。
答案 3 :(得分:0)
尝试使用array_mulisort。
答案 4 :(得分:0)
查看uasort以了解如何使用用户定义的比较功能。
答案 5 :(得分:0)
我目前正在创建一种排序方法,该方法由mysql查询中的值组成。
真相:
使用MySQL以外的任何东西对结果集进行排序将效率较低(对于php,usort()
或array_multisort()
调用会更好复杂且难以维护),因此不合适。
SQL:(Demo)
ORDER BY IF(LOCATE('EN', countries), 0, 1), id;
这会优先处理包含countries
的{{1}}列值,然后在EN
ASC上进行排序。
对于任何不处理sql结果集或由于某种原因无法操纵查询的人,我都支持id
。
PHP7提供了一个漂亮的新运算符,该运算符执行比较并返回三个值(-1、0、1)之一。这个运算符亲切地称为“太空飞船运算符”,看起来像usort()
。
PHP:(Demo)
<=>
输出:
$test = [
['id' => 1, 'countries' => 'EN,CH,SP'],
['id' => 2, 'countries' => 'GE,SP,SV'],
['id' => 3, 'countries' => 'PR,SP,IT'],
['id' => 4, 'countries' => 'EN'],
['id' => 5, 'countries' => 'SP,EN'],
['id' => 6, 'countries' => 'SV,SP,EN'],
['id' => 7, 'countries' => 'GE,SP'],
['id' => 8, 'countries' => 'FR'],
['id' => 9, 'countries' => 'RU,EN'],
['id' => 10, 'countries' => 'EN,SP,IT'],
['id' => 11, 'countries' => 'SP,GR'],
['id' => 12, 'countries' => 'GR,EN']
];
usort($test, function($a, $b) {
return [strpos($a['countries'], 'EN') === false, $a['id']] <=> [strpos($b['countries'], 'EN') === false, $b['id']];
});
var_export($test);
从左到右评估飞船运算符两侧的数组元素(左侧[0]与右侧[0],然后移动到一对[1]值,如果两者之间有“并列” [0]个值)。
如果array (
0 =>
array (
'id' => 1,
'countries' => 'EN,CH,SP',
),
1 =>
array (
'id' => 4,
'countries' => 'EN',
),
2 =>
array (
'id' => 5,
'countries' => 'SP,EN',
),
3 =>
array (
'id' => 6,
'countries' => 'SV,SP,EN',
),
4 =>
array (
'id' => 9,
'countries' => 'RU,EN',
),
5 =>
array (
'id' => 10,
'countries' => 'EN,SP,IT',
),
6 =>
array (
'id' => 12,
'countries' => 'GR,EN',
),
7 =>
array (
'id' => 2,
'countries' => 'GE,SP,SV',
),
8 =>
array (
'id' => 3,
'countries' => 'PR,SP,IT',
),
9 =>
array (
'id' => 7,
'countries' => 'GE,SP',
),
10 =>
array (
'id' => 8,
'countries' => 'FR',
),
11 =>
array (
'id' => 11,
'countries' => 'SP,GR',
),
)
向后看,让我解释一下...
如果在国家/地区字符串中找到=== false
,则条件的值为EN
。在比较false
和true
时,请记住false
等于1,而true
等于0。我们要进行ASC排序,因此我们想将假结果放在真实结果之前,包含false
需要的ergo字符串返回false。希望这可以清除逻辑。