2012-08-16 21 views
7

Me gustaría ordenar cadenas en PHP, y la coincidencia debe hacerse principalmente en las primeras letras de una subcadena, luego en las letras de toda la cadena.Ordenar cadenas, primeras letras primero, luego letras dentro de las palabras

Por ejemplo, si alguien busca do, y la lista contiene

Adolf 
Doe 
Done 

el resultado debe ser

Doe 
Done 
Adolf 

Usando los regulares sort($array, SORT_STRING) o cosas por el estilo no funciona, Adolf se ordena antes los demás.

¿Alguien tiene una idea de cómo hacerlo?

+1

No se puede hacer con una simple búsqueda. Le sugiero que cree una lista múltiple, para cada posición de la ocurrencia que está buscando, luego ordene estas sub-listas. – Tchoupi

+0

@ user1603166, su pregunta es ligeramente ambigua. Del ejemplo de @Roman, si la lista también incluye 'Odómetro' y' Abdomen', ¿cómo debería ordenarse? – Matthew

Respuesta

0

Puede ordenar las cadenas según stripos($str, $search) para que las que están en la parte delantera (stripos() == 0) salgan primero.

El siguiente código empuja las posiciones de la subcadena de la cadena de búsqueda en una matriz separada y luego usa array_multisort() para aplicar el orden correcto a las coincidencias; hacerlo de esta manera en lugar de usort() evita tener que llamar al stripos() muchas veces.

$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

Esta es una solución inteligente, pero fallará si la lista tiene cadenas que no contienen '$ search'. stripos() devolverá falso, que se equipara con 0. (Se rectifica fácilmente si el mapa de la matriz devuelve un número enorme en lugar de falso.) – Matthew

+0

@Matthew Asumo que la coincidencia ya se ha realizado usando un grep o algo :) –

+0

Of Por supuesto, idealmente eso debería hacerse en el mismo paso que la determinación de posición ;-) déjame pensar en eso. –

3

usort(array, callback) le permite ordenación en función de una devolución de llamada.

ejemplo (algo como esto, no lo probamos)

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

No entiendo tu respuesta. Ok usort, déjenme ordenar con una función por mi cuenta, pero el problema es que las funciones de clasificación me dan Adolf antes que Doe en este caso. – user1603166

+0

Ok, intentaré con eso, ¡gracias! – user1603166

+0

Dependiendo de cuántas comparaciones se realicen dentro del 'usort()' esto puede ser bastante pesado :) –

3

me gustaría utilizar una especie de encargo:

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

Salida:

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

+1.Aunque OP debería ser consciente de que aquí '' Odometer' se enumerará antes de 'Abdomen', que puede o no ser deseable. – Roman

+0

@Roman, creo que ese es el objetivo de la búsqueda. Pero si no, eliminar el control '$ diff' y' return' eliminaría ese comportamiento. – Matthew

+0

No sé, supongo que es utilizado por una especie de función de "autocompletar", en ese caso preferiría tener todos los resultados que 'no comiencen con $ needle' ordenados por alfabeto. – Roman

Cuestiones relacionadas