2010-08-10 9 views
40

Me he encontrado con una vieja aplicación que utiliza un identificador de tipo array nombre, por ejemplo ...¿Cómo puedo forzar a PHP a usar cadenas para claves de matriz?

array(1) { 
    [280]=> 
    string(3) "abc" 
} 

ahora tengo que cambiar el orden de estos, y una var_dump() podría hacer que parezca que no es va a suceder mientras que las claves son enteros.

Si añado un a a cada índice, var_dump() mostrará dobles comillas alrededor de la llave, mi conjetura para mostrar lo que es ahora una cadena ...

array(1) { 
    ["280a"]=> 
    string(3) "abc" 
} 

Esto me dejaría fácilmente cambiar su orden, sin tener que tocar más código.

Esto hace no funciona.

$newArray = array(); 
foreach($array as $key => $value) { 
    $newArray[(string) $key] = $value; 
} 

A var_dump() todavía los muestra como índices de matriz de enteros.

¿Hay alguna manera de forzar las teclas para que sean cuerdas, así que puedo reordenarlas sin arruinar la matriz?

+0

Tenía el mismo problema. Obtuve claves como "0", "1" en los datos de entrada (de http request) y quería filtrar utilizando 'array_intersect_key' ... parece que utilizaré otro enfoque. – kirilloid

+0

Posible duplicado de [Una cadena numérica como clave de matriz en PHP] (http://stackoverflow.com/questions/4100488/a-numeric-string-as-array-key-in-php) – Flimm

+0

@Flimm Se hizo esa pregunta después del mío, entonces es un duplicado de este. – alex

Respuesta

7

EDITAR:

que supone que si son números enteros, que no puedo reordenarlos sin cambiar la clave (que es significativo en este ejemplo). Sin embargo, si fueran cadenas , puedo reordenarlas como , ya que el índice no debe ser interpretado para tener cualquier significado especial . De todos modos, ver mi pregunta actualización de cómo lo hice (bajé por una ruta diferente ).

En realidad no tiene que estar en orden numérico ...

array(208=>'a', 0=> 'b', 99=>'c'); 

es perfectamente válido si usted está asignando manualmente. Aunque estoy de acuerdo en que las claves enteras podrían malinterpretarse como si tuvieran un significado secuencial por parte de alguien, aunque uno pensaría que si estuvieran en un orden no numérico sería evidente que no lo eran. Dicho esto, creo que ya que usted tuvo la libertad de cambiar el código cuando lo actualizó, ese es el mejor enfoque.


Probablemente no

la manera más eficiente, pero facilón:

$keys = array_keys($data); 

$values = array_values($data); 
$stringKeys = array_map('strval', $keys); 

$data = array_combine($stringKeys, $values); 

//sort your data 
+0

Los argumentos 'array_map' están en el camino equivocado. Pruébalo ahora, gracias. – alex

+0

Lo siento, no lo mencioné, pero esto está en un proyecto de PHP4 por lo que no 'array_combine()'. Voy a iterar y construirlo. – alex

+1

Bummer, no funcionó. Parece que se vuelven a convertir en enteros. Incluso intenté usar el operador de reparto '(cadena)'. No es hasta que agregue un no entero que cambian a la secuencia. – alex

9

¿qué tal esto?

$newArray = array(); 
foreach($oldArray as $key => $value) { 
    $newArray[$key.''] = $value; 
} 

edición: intentó eso también y sí, no funcionó.

Desde el PHP docs:

Una clave puede ser un número entero o una cadena .Si una clave es la representación estándar de un número entero, se interpretará como (es decir, "8" se se interpretará como 8, mientras que "08" se se interpretará como "08"). Los flotantes en la clave se truncan en enteros. No hay diferentes tipos de matrices indexadas y asociativas en PHP; solo hay un tipo de matriz , que puede contener enteros e índices de cadena.

Supongo que ahora depende de cómo se desea ordenar la matriz. (Salida final?)

+3

Desafortunadamente, he [probado eso] (http://codepad.org/1IqwfZUx) y no funciona. Gracias por pasar por Andy! – alex

+0

sí ¿cómo quieres ordenar la matriz exactamente? – prodigitalson

+0

@prodigitalson Supuse que si son enteros, no puedo reordenarlos sin cambiar la clave (lo cual es significativo en este ejemplo). Sin embargo, si fueran cadenas, puedo reordenarlas como quieran, ya que no debe interpretarse que el índice tenga un significado especial. De todos modos, mira la actualización de mi pregunta sobre cómo lo hice (seguí una ruta diferente). – alex

1

Editar: Esto debería funcionar

foreach($array as $key => $value) { 
    $newkey = sprintf('%s',$key); 
    $newArray["'$newkey'"] = $value; 
} 
+1

Interesante, pero esto solo agrega más complejidad, creo. – alex

+0

Echa un vistazo a la edición ... Creo que esto debería funcionar. – user387302

+0

En realidad, ahora que lo pienso, incluso hacer esto podría funcionar: $ newArray ["'$ key'"] = $ value – user387302

6

Utilice un objeto en lugar de una matriz $object = (object)$array;

+0

@ ÁlvaroGonzález puedes iterar cualquier objeto como una matriz, ¿no? Pasará por las propiedades disponibles en el alcance de la llamada. – nawfal

+0

@nawfal - Tiene razón, obtiene todas las propiedades públicas automáticamente. No estaba al tanto de esa característica. Eliminaré mi comentario para evitar la confusión. Gracias por el puntero. –

3

pude conseguir que esto funcione mediante la adición de' 0.0' en el final de cada clave, tales como:

$options = []; 
for ($i = 1; $i <= 4; $i++) { 
    $options[$i.'.0'] = $i; 
} 

volveremos: el

array("1.0" => 1, "2.0" => 2, "3.0" => 3, "4.0" => 4)

Puede que no sea completamente óptimo pero le permite ordenar la matriz y extraer (el equivalente de) la clave original sin tener que truncar nada.

+0

puede ser lo suficientemente bueno para algunos casos de uso. – ahnbizcad

6

¡NO PUEDE!

Las cadenas que contienen enteros válidos se convertirán al tipo de entero. P.ej. la clave "8" se almacenará en realidad en 8. Por otro lado, "08" no se emitirá, ya que no es un número entero decimal válido.

Editar:

En realidad se puede !! Cast sequential array to associative array

$obj = new stdClass; 
foreach($array as $key => $value){ 
    $obj->{$key} = $value; 
} 
$array = (array) $obj; 

En la mayoría de los casos, la siguiente cita es cierto.

Las cadenas que contienen números enteros válidos se convertirán al tipo de entero. P.ej. la clave "8" se almacenará en realidad en 8. Por otro lado, "08" no se emitirá, ya que no es un número entero decimal válido.

Este ejemplo de PHP Docs

<?php 
    $array = array(
     1 => "a", 
     "1" => "b", 
     1.5 => "c", 
     true => "d", 
    ); 
    var_dump($array); 
?> 

El resultado del ejemplo sería:

array(1) { 
    [1]=> string(1) "d" 
} 

Así que incluso si tuviera que crear una matriz con teclas numeradas que sólo conseguirían emitidos vuelta a enteros.

Desafortunadamente para mí no estaba al tanto de esto hasta hace poco pero pensé que compartiría mis intentos fallidos.

Los intentos fallidos

$arr = array_​change_​key_​case($arr); // worth a try. 

Devuelve una matriz con todas las claves de serie a mayúsculas o minúsculas. Los índices numerados se dejan como está.

Mis próximos intentos fueron crear una nueva matriz por array_combine ing old values ​​the new (string) keys.

Intenté varias maneras de hacer que la matriz $keys contenga valores numéricos de tipo cadena.

range("A", "Z") funciona para el alfabeto, así que pensé que lo intentaría con una cadena numérica.

$keys = range("0", (string) count($arr)); // integers 

Esto dio como resultado una matriz llena de teclas, pero todas eran del tipo int.

Aquí hay un par de intentos exitosos de crear una matriz con los valores de tipo cadena.

$keys = explode(',', implode(",", array_keys($arr))); // values strings 

$keys = array_map('strval', array_keys($arr)); // values strings 

Ahora solo para combinar los dos.

$arr = array_combine($keys, $arr); 

Esto es cuando descubrí que las cadenas numéricas están convertidas en enteros.

$arr = array_combine($keys, $arr); // int strings 
//assert($arr === array_values($arr)) // true. 

La única manera de cambiar las claves para cuerdas y mantener sus valores literales sería para prefijar la clave con un sufijo con un punto "00","01","02" o "0.","1.","2." decimal.

Puede lograrlo de esta manera.

$keys = explode(',', implode(".,", array_keys($arr)) . '.'); // added decimal point 
$arr = array_combine($keys, $arr); 

Por supuesto, esto es menos que ideal, ya que tendrá que apuntar a elementos de la matriz como este.

$arr["280."] 

He creado una pequeña función que se centrará en el elemento de la matriz correcta incluso si sólo se introduce el número entero y no a la nueva cadena.

function array_value($array, $key){ 

    if(array_key_exists($key, $array)){ 
     return $array[ $key ]; 
    } 
    if(is_numeric($key) && array_key_exists('.' . $key, $array)){ 
     return $array[ '.' . $key ]; 
    } 
    return null; 
} 

Uso

echo array_value($array, "208"); // "abc" 

Editar:

En realidad se puede !! Cast sequential array to associative array

Todo eso por nada

3

Puede anexar el carácter nulo "\0" hasta el final de la clave de la matriz. Esto hace que PHP no pueda interpretar la cadena como un entero. Todas las funciones de matriz (como array_merge()) trabajan en él. Además, ni siquiera var_dump() mostrará nada extra después de la cadena de números enteros.

Ejemplo:

$numbers1 = array(); 
$numbers2 = array(); 
$numbers = array(); 

$pool1 = array(111, 222, 333, 444); 
$pool2 = array(555, 666, 777, 888); 

foreach($pool1 as $p1) 
{ 
    $numbers1[$p1 . "\0"] = $p1; 
} 
foreach($pool2 as $p2) 
{ 
    $numbers2[$p2 . "\0"] = $p2; 
} 

$numbers = array_merge($numbers1, $numbers2); 

var_dump($numbers); 

La salida resultante será:

array(8) { 
    ["111"] => string(3) "111" 
    ["222"] => string(3) "222" 
    ["333"] => string(3) "333" 
    ["444"] => string(3) "444" 
    ["555"] => string(3) "555" 
    ["666"] => string(3) "666" 
    ["777"] => string(3) "777" 
    ["888"] => string(3) "888" 
} 

Sin la parte . "\0" la matriz resultante sería:

array(8) { 
    [0] => string(3) "111" 
    [1] => string(3) "222" 
    [2] => string(3) "333" 
    [3] => string(3) "444" 
    [4] => string(3) "555" 
    [5] => string(3) "666" 
    [6] => string(3) "777" 
    [7] => string(3) "888" 
} 

También ksort() también ignorará el nulo carácter que significa $numbers[111] y $numbers["111\0"] ambos tendrán el mismo peso en el algoritmo de clasificación.

La única desventaja de este método es que para acceder, por ejemplo $numbers["444"], usted realmente tiene que acceder a ella a través de $numbers["444\0"] y puesto que ni siquiera var_dump() mostrará que hay un carácter nulo al final, no hay ninguna pista de por qué obtienes "compensación indefinida". Así que solo use este truco si itera a través de un foreach() o quien termine manteniendo su código lo odiará.

-1

Solo un comentarista tiene este derecho, y la respuesta aceptada es mala. asort(), uasort() y arsort() son complementos que ordenan arrays mientras mantienen las asociaciones de teclas, y han existido desde la versión 4. RTFM, personas.

Cuestiones relacionadas