2012-08-16 12 views
7

Vorrei ordinare le stringhe in PHP e la corrispondenza deve essere eseguita prima sulle prime lettere di una sottostringa, quindi sulle lettere dell'intera stringa.Ordinamento stringhe, prima le lettere prima e poi le lettere all'interno delle parole

Per esempio, se qualcuno cerca do, e l'elenco contiene

Adolf 
Doe 
Done 

il risultato dovrebbe essere

Doe 
Done 
Adolf 

Utilizzando le normali sort($array, SORT_STRING) o cose del genere non funziona, Adolf è ordinato prima gli altri.

Qualcuno ha un'idea di come farlo?

+1

Non si può fare con una semplice ricerca. Ti suggerisco di creare più elenchi, per ogni posizione dell'evento che stai cercando, quindi ordinare questi sotto-elenchi. – Tchoupi

+0

@ user1603166, la tua domanda è leggermente ambigua. Dall'esempio di @ Roman, se l'elenco includesse anche "Odometer" e "Addome", come dovrebbe essere ordinato? – Matthew

risposta

0

È possibile ordinare le stringhe in base a stripos($str, $search) in modo che quelle in primo piano (stripos() == 0) vengano visualizzate per prime.

Il seguente codice sposta le posizioni della sottostringa della stringa di ricerca in una matrice separata e quindi utilizza array_multisort() per applicare l'ordinamento corretto alle corrispondenze; farlo in questo modo invece di usort() evita di dover chiamare stripos() molte volte.

$k = array_map(function($v) use ($search) { 
    return stripos($v, $search); 
}, $matches); 

// $k contains all the substring positions of the search string for all matches 

array_multisort($k, SORT_NUMERIC, $matches, SORT_STRING); 

// $matches is now sorted against the position 
+0

Questa è una soluzione intelligente, ma fallirà se la lista contiene stringhe che non contengono '$ search'. stripos() restituirà false, che è equiparato a 0. (Facilmente rettificato se la mappa di matrice restituisce un numero enorme invece di falso.) – Matthew

+0

@Matthew presumo che l'abbinamento sia già stato eseguito utilizzando grep o sth :) –

+0

Of Certo, idealmente dovrebbe essere fatto nello stesso passo della determinazione della posizione ;-) fammi pensare a quello. –

3

usort(array, callback) consente di ordinare sulla base di un callback.

esempio (qualcosa di simile, non provate)

usort($list, function($a, $b) { 
    $posa = strpos(tolower($a), 'do'); 
    $posb = strpos(tolower($b), 'do'); 
    if($posa != 0 && $posb != 0)return strcmp($a, $b); 
    if($posa == 0 && $posb == 0)return strcmp($a, $b); 
    if($posa == 0 && $posb != 0)return -1; 
    if($posa != 0 && $posb == 0)return 1; 
}); 
+0

Non capisco la tua risposta. Ok usort mi consente di ordinare con una funzione da solo, ma il problema è ancora che le funzioni di ordinamento mi danno Adolf prima di Doe in questo caso. – user1603166

+0

Ok ci proverò, grazie! – user1603166

+0

A seconda di quanti confronti vengono effettuati all'interno di 'usort()' questo può diventare piuttosto pesante :) –

3

userei un ordinamento personalizzato:

<?php 
$list = ['Adolf', 'Doe', 'Done']; 

function searchFunc($needle) 
{ 
    return function ($a, $b) use ($needle) 
    { 
    $a_pos = stripos($a, $needle); 
    $b_pos = stripos($b, $needle); 

    # if needle is found in only one of the two strings, sort by that one 
    if ($a_pos === false && $b_pos !== false) return 1; 
    if ($a_pos !== false && $b_pos === false) return -1; 

    # if the positions differ, sort by the first one 
    $diff = $a_pos - $b_pos; 
    # alternatively: $diff = ($b_pos === 0) - ($a_pos === 0) 
    if ($diff) return $diff; 

    # else sort by natural case 
    return strcasecmp($a, $b); 

    }; 
} 

usort($list, searchFunc('do')); 

var_dump($list); 

uscita:

array(3) { 
    [0] => 
    string(3) "Doe" 
    [1] => 
    string(4) "Done" 
    [2] => 
    string(5) "Adolf" 
} 
+1

+1.Sebbene OP dovrebbe essere consapevole che qui 'Odometer' sarà elencato prima di 'Addome', che può o non può essere desiderabile. – Roman

+0

@Roman, penso che sia il punto della ricerca. In caso contrario, la rimozione del controllo '$ diff' e' return' rimuoverà tale comportamento. – Matthew

+0

Non so, presumo sia usato da una sorta di funzione di "completamento automatico", in tal caso preferirei avere tutti i risultati che "non iniziano con $ ago" ordinati per alfabeto. – Roman

Problemi correlati