5

私は現在、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");

それをどのように進めるかについてのヒントを私に与えるかもしれない誰かがいますか?

4

4 に答える 4

12

個人的には、カスタム (匿名) 関数を と組み合わせて使用​​しusort()ます。

編集:再 - あなたのコメント。うまくいけば、これが正しい軌道に乗るでしょう。この関数は、EN を持つ要素または EN を持たない要素に同等の優先度を与えるか、EN を持つ要素が 1 つだけの場合に優先度を調整します。

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

注: このコードは、最高ランクの全体を配列の先頭に並べ替えます。逆の動作が必要な場合は、これを変更します。

    elseif ($aScore > $bScore) {

    elseif ($aScore < $bScore) {

大なり記号が小なり記号に変更されたことに注意してください。この変更を行うと、ランキングが最も低いエントリが配列の先頭にソートされます。これがすべて役立つことを願っています!

また注意してください!

このコードは、各配列に _score 要素を追加するという点で、配列に小さな変更を加えます。この値を保存することで、文字通り2倍以上速度を上げることができたので、これが問題にならないことを願っています(私のベンチマークでは.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,
  ),
)

楽しみ!

于 2010-01-13T18:50:31.570 に答える
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));

助けてくれてありがとう!

于 2010-01-13T22:30:56.680 に答える
1

array_walkとを検討するかもしれません。これを組み合わせるarray_walk_recursivearray_map、やりたいことを実行できるようになります。

于 2010-01-13T18:43:59.263 に答える