Tri réseau MultiDim: donner la priorité si la colonne contient des sous-chaîne, puis par ordre une seconde colonne

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

Question

Je crée actuellement une méthode de tri qui se compose de valeurs à partir d'une requête mysql.

Voici une brève vue du tableau:

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

J'ai réussi à faire une usort normale sur la base des valeurs id numériques, mais je veux plutôt pour trier le tableau par le contenu du champ « pays » (si elle contient une chaîne de jeu, un code de pays dans ce cas) , puis par le champ id.

L'extrait suivant était ma première idée de la façon de le faire, mais je ne sais pas comment l'intégrer dans une fonction de travail:

in_array('EN', explode(",",$a['countries']) );

Comment voulez-vous faire?

Merci!


Je suis vraiment nulle part avec ce malheureusement.

Voici ce que j'ai pour le moment, et me donner son qu'erreurs: 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");

Y at-il quelqu'un qui pourrait me donner une idée de la façon d'aller avec elle?

Était-ce utile?

La solution

Personnellement, j'utiliser une fonction personnalisée (anonyme) en collaboration avec usort() .

EDIT: Re - votre commentaire. Espérons que cela vous mettra sur la bonne voie. Cette fonction donne la priorité égale à des éléments qui ont tous deux EN ou qui ne sont point EN, ou la priorité ajustée alors qu'un seul a FR.

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

Cette fonction, d'autre part, donne la même priorité si les deux ont EN, plus si l'on a FR, et fait une comparaison de texte si ni a FR.

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

Encore une fois, nous espérons que cela vous donnera la direction assez pour aller de l'avant sur votre propre. Si vous rencontrez des problèmes, ne hésitez pas à poster plus de commentaires et je vais essayer de vous aider. Une note si vous attacher à comparer les propriétés multiples avec le poids. Essayer un bloc interrupteur génial, par exemple

$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
}

Plus Edits!

En fait, je pensais plus sur le problème de tri complexe, et je suis venu avec la solution suivante, pour examen. Il vous permettra de définir les classements numériques basés sur des mots clés qui apparaissent dans l'indice des pays. Voici le code, y compris un exemple:

Exemple Tableau

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

);

Tri de routine

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

Note: Ce code triera les plus haut rang entires au sommet du tableau . Si vous voulez inverser le comportement, changer ceci:

    elseif ($aScore > $bScore) {

à

    elseif ($aScore < $bScore) {

Notez que plus-que a été remplacé par un symbole inférieur. Cette modification entraînera les entrées le plus bas classement étant triée au sommet du tableau . Je espère que tout cela aide!

NOTE AUSSI!

Ce code fera un petit changement à votre tableau, en ce qu'elle ajoute l'élément _SCORE à chaque tableau. Espérons que ce n'est pas un problème, en stockant cette valeur, je suis littéralement en mesure d'augmenter la vitesse de plus que le double (0,00038-0,00041 jusqu'à 0,00016-,00018 dans mes points de référence). Sinon, retirez les blocs de if qui récupèrent la valeur mise en cache et de laisser le contenu des blocs de else exécutent chaque fois, sauf bien sûr pour la partie qui stocke la valeur de score.

Par ailleurs, voici une décharge var_export() du tableau après avoir été triée:

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

Amusez-vous!

Autres conseils

Enfin trouvé cette fonction merveilleuse à 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;

        }

Voici comment chaque pays ressemble à: $ Array [ 'pays'] = in_array ($ needle, botte de foin $);                         }

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

Merci à tous pour votre aide!

Consultez uasort pour voir comment utiliser un utilisateur défini fonction de comparaison.

  

Je crée actuellement une méthode de tri qui se compose de valeurs à partir d'une requête mysql.

VÉRITÉ: En utilisant autre chose que MySQL pour trier votre jeu de résultats sera moins efficace (avec php, un appel usort() ou array_multisort() sera plus compliqué et plus difficile à maintenir) et, par conséquent inappropriée .

SQL: ( Demo )

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

priorise les valeurs des colonnes qui contiennent countries EN trie sur id ASC.


Pour toute personne qui manipule pas un jeu de résultats SQL ou ne peut pas manipuler la requête pour une raison quelconque, je souscris usort(). PHP7 offre une belle nouvel opérateur qui réalise une comparaison et retourne une des trois valeurs (-1, 0, 1). Cet opérateur est affectueusement appelé « opérateur de vaisseau spatial » et ressemble à ceci <=>.

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

Sortie:

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

Les éléments du tableau de chaque côté de l'opérateur de vaisseau spatial sont évaluées de gauche à droite (leftside [0] vs rightside [0], se déplaçant ensuite sur la paire de valeurs [1] s'il y a un « lien » entre les deux [0] des valeurs).

Si le === false regarde en arrière, laissez-moi vous expliquer ...

Si EN se trouve dans la chaîne de pays, la condition évaluera comme false. Lorsque l'on compare true et false, rappelez-vous que true équivaut à 1 et false équivaut à 0. Nous voulons le tri des ASC, donc nous voulons mettre les résultats faux avant que les résultats réels, les chaînes de ergo contenant EN besoin return false. Il faut espérer que la logique efface.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top