2008-12-08 25 views
109

¿Es posible en PHP hacer algo como esto? ¿Cómo harías para escribir una función? Aquí hay un ejemplo. El orden es lo más importante.Ordenar una matriz por claves basadas en otra matriz?

$customer['address'] = '123 fake st'; 
$customer['name'] = 'Tim'; 
$customer['dob'] = '12/08/1986'; 
$customer['dontSortMe'] = 'this value doesnt need to be sorted'; 

Y me gustaría hacer algo como

$properOrderedArray = sortArrayByArray($customer, array('name', 'dob', 'address')); 

Porque al final utilizo un foreach() y que no están en el orden correcto (porque añado los valores a una cadena que debe estar en el orden correcto y no sé de antemano todas las claves/valores de la matriz).

He revisado las funciones de matriz internas de PHP, pero parece que solo se puede ordenar alfabéticamente o numéricamente.

Respuesta

267

Simplemente use array_merge o array_replace. Array_merge obras de comenzar con la matriz que le dan (en el orden correcto) y sobrescribir/adición de las teclas con los datos de la matriz real:

$customer['address'] = '123 fake st'; 
$customer['name'] = 'Tim'; 
$customer['dob'] = '12/08/1986'; 
$customer['dontSortMe'] = 'this value doesnt need to be sorted'; 

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer); 
//Or: 
$properOrderedArray = array_replace(array_flip(array('name', 'dob', 'address')), $customer); 

//$properOrderedArray -> array('name' => 'Tim', 'address' => '123 fake st', 'dob' => '12/08/1986', 'dontSortMe' => 'this value doesnt need to be sorted') 

PS - Estoy responder a esta pregunta 'rancio', porque piense que todos los bucles dados como respuestas anteriores son excesivos.

+22

Funciona muy bien si tiene claves de cadena, pero no para la numérica. PHP Docs: "Si las matrices de entrada tienen las mismas claves de cadena, el valor posterior de esa tecla sobrescribirá la anterior. Sin embargo, si las matrices contienen claves numéricas, el valor posterior no sobrescribirá el valor original, pero se adjuntará ". – bolbol

+3

Bien, pero ¿y si las claves no existen en los valores? Necesito esto, pero solo si existe alguna de las claves ... Probablemente necesito un foreach entonces ... –

+4

para mi caso es array_replace en lugar de array_merge. array_merge combina ambos valores en lugar de reemplazar la segunda matriz en las claves ordenadas. – neofreko

89

ahí lo tienes:

function sortArrayByArray(array $array, array $orderArray) { 
    $ordered = array(); 
    foreach ($orderArray as $key) { 
     if (array_key_exists($key, $array)) { 
      $ordered[$key] = $array[$key]; 
      unset($array[$key]); 
     } 
    } 
    return $ordered + $array; 
} 
+11

Entonces, ¿puede unir 2 matrices con un signo +? ¡Nunca lo supe, he estado usando 'array_merge()'! – alex

+3

¿Es esto mejor que usar 'usort()' o 'uasort()'? – grantwparks

+2

'foreach ($ orderArray as $ key => $ v)' fue el truco para mí –

21
function sortArrayByArray(array $toSort, array $sortByValuesAsKeys) 
{ 
    $commonKeysInOrder = array_intersect_key(array_flip($sortByValuesAsKeys), $toSort); 
    $commonKeysWithValue = array_intersect_key($toSort, $commonKeysInOrder); 
    $sorted = array_merge($commonKeysInOrder, $commonKeysWithValue); 
    return $sorted; 
} 
2

SI usted tiene matriz en la matriz, se tendrá que adaptar la función de Eran un poco ...

function sortArrayByArray($array,$orderArray) { 
    $ordered = array(); 
    foreach($orderArray as $key => $value) { 
     if(array_key_exists($key,$array)) { 
       $ordered[$key] = $array[$key]; 
       unset($array[$key]); 
     } 
    } 
    return $ordered + $array; 
} 
13

Take una matriz como su orden:

$order = array('north', 'east', 'south', 'west'); 

Y ou puede ordenar otra matriz basada en los valores usando array_intersect­Docs:

/* sort by value: */ 
$array = array('south', 'west', 'north'); 
$sorted = array_intersect($order, $array); 
print_r($sorted); 

o en su caso, para ordenar por teclas, utilice array_intersect_key­Docs:

/* sort by key: */ 
$array = array_flip($array); 
$sorted = array_intersect_key(array_flip($order), $array); 
print_r($sorted); 

Ambas funciones se mantendrá el orden del primer parámetro y la voluntad solo devuelve los valores (o claves) de la segunda matriz.

Por lo tanto, para estos dos casos estándar no necesita escribir una función por su cuenta para realizar la clasificación/reordenación.

+0

La intersección eliminaría aquellas entradas que no sabe de antemano. – DanMan

+1

Esto es incorrecto para ordenar por claves. array_intersect_key solo devolverá los valores de array1, no array2 – pavsid

+0

Acordado con pavsid - el ejemplo de array_intersect_key es incorrecto - devuelve los valores de la primera matriz, no la segunda. –

0

primera sugerencia

function sortArrayByArray($array,$orderArray) { 
    $ordered = array(); 
    foreach($orderArray as $key) { 
     if(array_key_exists($key,$array)) { 
      $ordered[$key] = $array[$key]; 
      unset($array[$key]); 
     } 
    } 
    return $ordered + $array; 
} 

segunda sugerencia

$properOrderedArray = array_merge(array_flip(array('name', 'dob', 'address')), $customer); 

Yo quería señalar que tanto de estas sugerencias son impresionantes. Sin embargo, son manzanas y naranjas. ¿La diferencia? Uno es amigable no asociativo y el otro amigable asociativo. Si está utilizando 2 matrices totalmente asociativas, la combinación merge/flip se fusionará y sobreescribirá la otra matriz asociativa. En mi caso, esos no son los resultados que estaba buscando. Usé un archivo settings.ini para crear mi matriz de orden de clasificación. La matriz de datos que estaba ordenando no necesitaba ser escrita por mi contraparte de ordenación asociativa. Por lo tanto, la combinación de array destruiría mi matriz de datos.Ambos son excelentes métodos, ambos deben archivarse en cualquier caja de herramientas de desarrollo. Según sus necesidades, es posible que realmente necesite ambos conceptos en sus archivos.

0

que adoptó la respuesta de @ Darkwaltz4 por su brevedad y me gustaría compartir cómo me he adaptado la solución a situaciones en las que la matriz puede contener claves diferentes para cada iteración de este modo:

Array[0] ... 
['dob'] = '12/08/1986'; 
['some_key'] = 'some value'; 

Array[1] ... 
['dob'] = '12/08/1986'; 

Array[2] ... 
['dob'] = '12/08/1986'; 
['some_key'] = 'some other value'; 

y mantuvieron una " llave maestra" de esta manera:

$master_key = array('dob' => ' ' , 'some_key' => ' '); 

array_merge habría ejecutado la fusión de la matriz [1] iteración basado en $ master_key y producido [ 'some_key'] = '', un valor vacío, para esa iteración. Por lo tanto, se utilizó para modificar array_intersect_key $ master_key en cada uno de iteraciones de este modo:

foreach ($customer as $customer) { 
    $modified_key = array_intersect_key($master_key, $unordered_array); 
    $properOrderedArray = array_merge($modified_key, $customer); 
} 
33

Otra forma para PHP> = 5.3.0:

$customer['address'] = '123 fake st'; 
$customer['name'] = 'Tim'; 
$customer['dob'] = '12/08/1986'; 
$customer['dontSortMe'] = 'this value doesnt need to be sorted'; 

$customerSorted = array_replace(array_flip(array('name', 'dob', 'address')), $customer); 

Resultado:

Array (
    [name] => Tim 
    [dob] => 12/08/1986 
    [address] => 123 fake st 
    [dontSortMe] => this value doesnt need to be sorted 
) 

funciona bien con cuerdas y teclas numéricas.

+1

+ Mientras ambos funcionan, encontré 'array_replace()' para retransmitir el intento mejor que 'array_merge()'. –

+0

'array_replace' también deja intacto el tipo de variable. Si uno de los valores en su matriz hubiera sido '(cadena) '1'' y hubiera utilizado el operador' + ', el valor se habría convertido en' (int) 1' –

+0

Esto también funciona en numérico keys ('array_merge()' simplemente los anexaría?). La lógica está muy bien explicada [aquí] (https://www.designcise.com/web/tutorial/how-to-sort-an-array-by-keys-based-on-order-in-a-secondary- array-in-php). * Primero *, 'array_flip()' cambia los valores de la matriz $ order a keys. * Segundo *, 'array_replace()' reemplaza los valores de la primera matriz con valores que tienen las mismas claves en la segunda matriz. Si necesita ordenar una matriz según las claves de otra, ni siquiera tiene que usar 'array_flip'. –

0

PHP tiene funciones para ayudarle con esto:

$arrayToBeSorted = array('west', 'east', 'south', 'north'); 
$order = array('north', 'south', 'east', 'west'); 

// sort array 
usort($arrayToBeSorted, function($a, $b) use ($order){ 
    // sort using the numeric index of the second array 
    $valA = array_search($a, $order); 
    $valB = array_search($b, $order); 

    // move items that don't match to end 
    if ($valA === false) 
     return -1; 
    if ($valB === false) 
     return 0; 

    if ($valA > $valB) 
     return 1; 
    if ($valA < $valB) 
     return -1; 
    return 0; 
}); 

usort hace todo el trabajo para usted y array_search proporciona las claves. array_search() devuelve falso cuando no puede encontrar una coincidencia para que los elementos que no están en la matriz de clasificación se muevan naturalmente al final de la matriz.

Nota: uasort() ordenará la matriz sin afectar las relaciones clave => valor.

23

¿Qué hay de esta solución

$order = array(1,5,2,4,3,6); 

$array = array(
    1 => 'one', 
    2 => 'two', 
    3 => 'three', 
    4 => 'four', 
    5 => 'five', 
    6 => 'six' 
); 

uksort($array, function($key1, $key2) use ($order) { 
    return (array_search($key1, $order) > array_search($key2, $order)); 
}); 
-1

Un poco tarde, pero no pude encontrar la manera de que se implemente, esta versión necesita el cierre, PHP> = 5.3, pero podría ser alterado a no:

$customer['address'] = '123 fake st'; 
$customer['name'] = 'Tim'; 
$customer['dob'] = '12/08/1986'; 
$customer['dontSortMe'] = 'this value doesnt need to be sorted'; 

$order = array('name', 'dob', 'address'); 

$keys= array_flip($order); 
uksort($customer, function($a, $b)use($keys){ 
    return $keys[$a] - $keys[$b]; 
}); 
print_r($customer); 

Por supuesto 'dontSortMe' tiene que ser resuelto, y puede aparecer por primera vez en el ejemplo

0
  • especie conforme a lo solicitado
  • , salvo por INT teclas (debido a array_replace)
  • no vuelven claves no son existentes en inputArray
  • (opcionalmente) las teclas de filtro no existentes en dado keyList

Código:

/** 
* sort keys like in key list 
* filter: remove keys are not listed in keyList 
* ['c'=>'red', 'd'=>'2016-12-29'] = sortAndFilterKeys(['d'=>'2016-12-29', 'c'=>'red', 'a'=>3 ]], ['c', 'd', 'z']){ 
* 
* @param array $inputArray 
* @param string[]|int[] $keyList 
* @param bool $removeUnknownKeys 
* @return array 
*/ 
static public function sortAndFilterKeys($inputArray, $keyList, $removeUnknownKeys=true){ 
    $keysAsKeys = array_flip($keyList); 
    $result = array_replace($keysAsKeys, $inputArray); // result = sorted keys + values from input + 
    $result = array_intersect_key($result, $inputArray); // remove keys are not existing in inputArray 
    if($removeUnknownKeys){ 
     $result = array_intersect_key($result, $keysAsKeys); // remove keys are not existing in keyList 
    } 
    return $result; 
} 
1

Esta función devuelve un sub y la matriz ordenada basada en claves $ segundo parámetro

function array_sub_sort(array $values, array $keys){ 
    $keys = array_flip($keys); 
    return array_merge(array_intersect_key($keys, $values), array_intersect_key($values, $keys)); 
} 

Ejemplo:

$array_complete = [ 
    'a' => 1, 
    'c' => 3, 
    'd' => 4, 
    'e' => 5, 
    'b' => 2 
]; 

$array_sub_sorted = array_sub_sort($array_complete, ['a', 'b', 'c']);//return ['a' => 1, 'b' => 2, 'c' => 3]; 
1

Solía ​​solución del Darkwaltz4 sino que se utiliza array_fill_keys en lugar de array_flip, para completar con NULL si una clave no está configurada en $array.

$properOrderedArray = array_replace(array_fill_keys($keys, null), $array); 
Cuestiones relacionadas