对 multidim 数组进行排序:如果列包含子字符串,则优先排序,然后按第二列排序

StackOverflow https://stackoverflow.com/questions/2059255

我目前正在创建一个由 mysql 查询中的值组成的排序方法。

这是数组的简要视图:

    Array
    (
        [0] => Array
            (
                ['id'] = 1;
                ['countries'] = 'EN,CH,SP';
            )
        [1] => Array
            (
                ['id'] = 2;
                ['countries'] = 'GE,SP,SV';
            )
    )

我已经成功地根据数字 id 值进行正常的 usort,但我更想按“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");

有没有人可以给我一个提示,告诉我如何继续下去?

有帮助吗?

解决方案

个人而言,我使用自定义与 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;
        }
    }
});

再次希望这会给你足够的方向在自己的前进。如果您有任何问题,随意张贴更多的意见,我会尽力帮助。 如果你绑到多个性能与重量比的注意事项:尝试了一个时髦的开关块,e.g

$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元件到每个阵列。但愿这不是一个问题,因为通过存储这个值我从字面上能够通过增加一倍以上(0.00038,0.00041降至0.00016,0.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,
  ),
)

享受!

其他提示

最后发现这个精彩功能在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;

        }

这是各个国家的样子: $阵列[ '国家'] = in_array($针,$草堆);                         }

$array = $array = array_msort($array, array('countries'=>SORT_DESC, 'id'=>SORT_ASC));

感谢所有您的帮助!

你可能会考虑 array_walkarray_walk_recursivearray_map, ,当组合在一起时也许可以做你想做的事情。

与尝试 array_mulisort

查核 uasort 来看看如何使用用户定义的比较函数。

  

我目前创建包含值从MySQL查询分拣方法。

真相:点击使用MySQL之外的任何排序结果集的效率会降低(与PHP,一个usort()array_multisort()通话将更加令人费解和难以维持),因此不恰当

SQL:(演示

ORDER BY IF(LOCATE('EN', countries), 0, 1), id;

这个优先包含countries然后各种各样上EN ASC id列值。


对于任何人谁不处理一个SQL结果集或无法操纵查询出于某种原因,我赞同usort()。 PHP7提供了进行比较,并返回三个值(-1,0,1)中的一个美丽的新的运营商。这个操作符被亲切称为“飞船操作者”和看起来像这样<=>

PHP:(演示

$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);

输出:

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',
  ),
)

上宇宙飞船操作者两侧的数组元素从左到右(莱夫特赛德[0] VS rightside评价[0],然后移动到所述一对[1]的值,如果有一个“扎”在两者之间[0]的值)。

如果该=== false看起来倒退,让我解释...

如果在各国家的串中发现EN,条件将评估为false。当比较truefalse,请记住,true相当于1 false等于0。我们希望ASC排序,所以我们希望把假的结果之前真正的成果,包含EN ERGO字符串的需要的返回false。希望这清除了的逻辑。

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top