¿Cómo reindexar una matriz en PHP?

157

Tengo la siguiente matriz, que me gustaría reindexar para que las teclas se inviertan (idealmente comenzando en 1):

Matriz actual ( editar: la matriz en realidad se ve así):

Array (

[2] => Object
    (
        [title] => Section
        [linked] => 1
    )

[1] => Object
    (
        [title] => Sub-Section
        [linked] => 1
    )

[0] => Object
    (
        [title] => Sub-Sub-Section
        [linked] => 
    )

)

Como debería ser:

Array (

[1] => Object
    (
        [title] => Section
        [linked] => 1
    )

[2] => Object
    (
        [title] => Sub-Section
        [linked] => 1
    )

[3] => Object
    (
        [title] => Sub-Sub-Section
        [linked] => 
    )

)
melancólico
fuente
1
¿Dónde hay algo invertido?
Gumbo
Vea mi edición del primer ejemplo
meleyal
¿Y por qué necesitas que el índice del primer elemento sea 1? ¿Solo es un asunto de formato o para procesamiento interno?
Gumbo
Se utilizará como parámetro para que una función obtenga el segmento a url, algo así como get_url_segment (1) volvería, por ejemplo, en esta página "preguntas"
meleyal

Respuestas:

445

Si desea volver a indexar a partir de cero, simplemente haga lo siguiente:

$iZero = array_values($arr);

Si lo necesita para comenzar en uno, use lo siguiente:

$iOne = array_combine(range(1, count($arr)), array_values($arr));

Aquí están las páginas del manual para las funciones utilizadas:

Andrew Moore
fuente
1
Debe usar range (0, count ($ arr) - 1) para obtener una matriz indexada a cero.
Max Hartshorn
Es genial, alternativamente, puede intentar usar array_unshift ($ arr, '') para agregar un elemento indexado a cero, luego desarmar ($ arr [0]) para eliminarlo, moviendo así todos los índices hacia arriba en uno. Tal vez sea más rápido que array_combine (). O no :)
Steve Horvath
Tenga en cuenta que array_valuesdevuelve una copia de la matriz. Entonces, si tiene referencias a la matriz, entonces array_splicesería mejor. Ver solución @imagiro.
Nux
Solo array_values()haga que funcione, si comienza con el índice 0 todo el tiempo.
kishor10d
55

Aquí está la mejor manera :

# Array
$array = array('tomato', '', 'apple', 'melon', 'cherry', '', '', 'banana');

eso vuelve

Array
(
    [0] => tomato
    [1] => 
    [2] => apple
    [3] => melon
    [4] => cherry
    [5] => 
    [6] => 
    [7] => banana
)

al hacer esto

$array = array_values(array_filter($array));

obtienes esto

Array
(
    [0] => tomato
    [1] => apple
    [2] => melon
    [3] => cherry
    [4] => banana
)

Explicación

array_values() : Devuelve los valores de la matriz de entrada e indexa numéricamente.

array_filter(): Filtra los elementos de una matriz con una función definida por el usuario (UDF si no se proporciona ninguno , se eliminarán todas las entradas en la tabla de entrada con valor FALSO ).

Sandra
fuente
3
Si no le importa el orden, también puede ordenar ($ array);
Peter M. Elias
array_filter()parece completamente irrelevante para los datos de muestra.
mickmackusa
13

Me acabo de enterar que también puedes hacer un

array_splice($ar, 0, 0);

Eso hace la reindexación en el lugar, por lo que no terminas con una copia de la matriz original.

imagiro
fuente
9

¿Por qué reindexar? Simplemente agregue 1 al índice:

foreach ($array as $key => $val) {
    echo $key + 1, '<br>';
}

Editar    Después de que se haya aclarado la pregunta: puede usar el array_valuespara restablecer el índice comenzando en 0. Luego, puede usar el algoritmo anterior si solo desea que los elementos impresos comiencen en 1.

Gumbo
fuente
respuesta subestimada a esta pregunta :)
jminkler
6

Bueno, me gustaría pensar que, sea cual sea su objetivo final, no necesitaría modificar la matriz para que esté basada en 1 en lugar de 0, sino que podría manejarla en el momento de la iteración como Gumbo publicó.

Sin embargo , para responder a su pregunta, esta función debe convertir cualquier matriz en una versión basada en 1

function convertToOneBased( $arr )
{
    return array_combine( range( 1, count( $arr ) ), array_values( $arr ) );
}

EDITAR

Aquí hay una función más reutilizable / flexible, si lo desea

$arr = array( 'a', 'b', 'c' );

echo '<pre>';
print_r( reIndexArray( $arr ) );
print_r( reIndexArray( $arr, 1 ) );
print_r( reIndexArray( $arr, 2 ) );
print_r( reIndexArray( $arr, 10 ) );
print_r( reIndexArray( $arr, -10 ) );
echo '</pre>';

function reIndexArray( $arr, $startAt=0 )
{
    return ( 0 == $startAt )
        ? array_values( $arr )
        : array_combine( range( $startAt, count( $arr ) + ( $startAt - 1 ) ), array_values( $arr ) );
}
Peter Bailey
fuente
5

Esto hará lo que quieras:

<?php

$array = array(2 => 'a', 1 => 'b', 0 => 'c');

array_unshift($array, false); // Add to the start of the array
$array = array_values($array); // Re-number

// Remove the first index so we start at 1
$array = array_slice($array, 1, count($array), true);

print_r($array); // Array ( [1] => a [2] => b [3] => c ) 

?>
Greg
fuente
5

Es posible que desee considerar por qué desea utilizar una matriz basada en 1. Las matrices basadas en cero (cuando se utilizan matrices no asociativas) son bastante estándar, y si desea generar una salida a una interfaz de usuario, la mayoría manejaría la solución simplemente aumentando el número entero tras la salida a la interfaz de usuario.

Piense en la coherencia, tanto en su aplicación como en el código con el que trabaja, cuando piense en indexadores basados ​​en 1 para matrices.

Michael Trausch
fuente
2
Esto se correlaciona directamente con la separación entre la capa empresarial y la capa de presentación. Si está modificando el código en su lógica para acomodar la presentación, está haciendo cosas malas. Por ejemplo, si hizo esto para un controlador, de repente su controlador está vinculado a un renderizador de vistas específico en lugar de preparar datos para cualquier renderizador de vistas que pueda utilizar (php, json, xml, rss, etc.)
Tres
5

Una solución más elegante:

$list = array_combine(range(1, count($list)), array_values($list));

Ionuţ Pleşca
fuente
66
¿Llamas a esto elegante?
Julian
5

Puede reindexar una matriz para que la nueva matriz comience con un índice de 1 como este;

$arr = array(
  '2' => 'red',
  '1' => 'green',
  '0' => 'blue',
);

$arr1 = array_values($arr);   // Reindex the array starting from 0.
array_unshift($arr1, '');     // Prepend a dummy element to the start of the array.
unset($arr1[0]);              // Kill the dummy element.

print_r($arr);
print_r($arr1);

El resultado de lo anterior es;

Array
(
    [2] => red
    [1] => green
    [0] => blue
)
Array
(
    [1] => red
    [2] => green
    [3] => blue
)
Nigel Alderton
fuente
No tienes que usar array_valuesaquí. Mira mi respuesta.
Lluvia
4

Similar a @monowerker, necesitaba reindexar una matriz usando la clave de un objeto ...

$new = array();
$old = array(
  (object)array('id' => 123),
  (object)array('id' => 456),
  (object)array('id' => 789),
);
print_r($old);

array_walk($old, function($item, $key, &$reindexed_array) {
  $reindexed_array[$item->id] = $item;
}, &$new);

print_r($new);

Esto resultó en:

Array
(
    [0] => stdClass Object
        (
            [id] => 123
        )
    [1] => stdClass Object
        (
            [id] => 456
        )
    [2] => stdClass Object
        (
            [id] => 789
        )
)
Array
(
    [123] => stdClass Object
        (
            [id] => 123
        )
    [456] => stdClass Object
        (
            [id] => 456
        )
    [789] => stdClass Object
        (
            [id] => 789
        )
)
Mella
fuente
3
$tmp = array();
foreach (array_values($array) as $key => $value) {
    $tmp[$key+1] = $value;
}
$array = $tmp;
Tom Haigh
fuente
3

Si no está intentando reordenar la matriz, simplemente puede hacer:

$ array = array_reverse ($ array);
$ array = array_reverse ($ array);

El array_reverse es muy rápido y se reordena a medida que se invierte. Alguien más me mostró esto hace mucho tiempo. Por lo tanto, no puedo tomar crédito por haberlo inventado. Pero es muy simple y rápido.

marca
fuente
2

Similar a la contribución de Nick, llegué a la misma solución para reindexar una matriz, pero mejoré un poco la función ya que desde la versión 5.4 de PHP, no funciona debido a que pasa variables por referencia. La función de reindexación de ejemplo es así usando el usecierre de palabra clave:

function indexArrayByElement($array, $element)
{
    $arrayReindexed = [];
    array_walk(
        $array,
        function ($item, $key) use (&$arrayReindexed, $element) {
            $arrayReindexed[$item[$element]] = $item;
        }
    );
    return $arrayReindexed;
}
FantomX1
fuente
1

Aquí está mi propia implementación. Las claves en la matriz de entrada se volverán a numerar con claves incrementales a partir de $ start_index.

function array_reindex($array, $start_index)
{
    $array = array_values($array);
    $zeros_array = array_fill(0, $start_index, null);
    return array_slice(array_merge($zeros_array, $array), $start_index, null, true);
}
Mustapha Hadid
fuente
1

Simplemente haz esto:

<?php

array_push($array, '');
$array = array_reverse($array);
array_shift($array);
Roham Rafii
fuente
1

Puede hacerlo fácilmente después de usar la función array_values ​​() y array_filter () juntas para eliminar elementos de matriz vacíos y reindexar una matriz en PHP.

Función array_filter () La función PHP array_filter () elimina elementos o valores de matriz vacíos de una matriz en PHP. Esto también eliminará los valores en blanco, nulo, falso, 0 (cero).

Función array_values ​​() La función PHP array_values ​​() devuelve una matriz que contiene todos los valores de una matriz. La matriz devuelta tendrá teclas numéricas, comenzando en 0 y aumentará en 1.

Eliminar elementos de matriz vacíos y reindexar

Primero veamos la salida de la matriz $ stack:

<?php
  $stack = array("PHP", "HTML", "CSS", "", "JavaScript", null, 0);
  print_r($stack);
?>

Salida:

Array
(
    [0] => PHP
    [1] => HTML
    [2] => CSS
    [3] => 
    [4] => JavaScript
    [5] => 
    [6] => 0
)

En la salida anterior, queremos eliminar los valores en blanco, nulos, 0 (cero) y luego reindexar los elementos de la matriz. Ahora usaremos la función array_values ​​() y array_filter () juntas como en el siguiente ejemplo:

<?php
  $stack = array("PHP", "HTML", "CSS", "", "JavaScript", null, 0);
  print_r(array_values(array_filter($stack)));
?>

Salida:

Array
(
    [0] => PHP
    [1] => HTML
    [2] => CSS
    [3] => JavaScript
)
Estrella
fuente
array_filter()parece completamente irrelevante para los datos de muestra del OP.
mickmackusa
1

Eliminación duplicada y reindexar una matriz:

<?php  
   $oldArray = array('0'=>'php','1'=>'java','2'=>'','3'=>'asp','4'=>'','5'=>'mysql');
   //duplicate removal
   $fillteredArray = array_filter($oldArray);
   //reindexing actually happens  here
   $newArray = array_merge($filteredArray);
   print_r($newArray);
?>
Sam T
fuente
array_filter()parece completamente irrelevante para los datos de muestra del OP.
mickmackusa
1

La forma más rápida que se me ocurre

array_unshift($arr, null);
unset($arr[0]);
print_r($arr);

Y si solo desea reindexar la matriz (comenzar en cero) y tiene PHP +7.3, puede hacerlo de esta manera

array_unshift($arr);

Creo que array_unshiftes mejor que array_valuesya que el primero no crea una copia de la matriz.

Lluvia
fuente
0

Parece que todas las array_combine()respuestas están copiando el mismo "error" (la llamada innecesaria de array_values()).

array_combine() ignora las claves de ambos parámetros que recibe.

Código: ( Demo )

$array = [
    2 => (object)['title' => 'Section', 'linked' => 1],
    1 => (object)['title' => 'Sub-Section', 'linked' => 1],
    0 => (object)['title' => 'Sub-Sub-Section', 'linked' => null]
];

var_export(array_combine(range(1, count($array)), $array));

Salida:

array (
  1 => 
  (object) array(
     'title' => 'Section',
     'linked' => 1,
  ),
  2 => 
  (object) array(
     'title' => 'Sub-Section',
     'linked' => 1,
  ),
  3 => 
  (object) array(
     'title' => 'Sub-Sub-Section',
     'linked' => NULL,
  ),
)
mickmackusa
fuente
0

La ordenación es solo un sort () , reindexar parece un poco tonto, pero si es necesario, esto lo hará. Aunque no en el lugar. Use array_walk () si va a hacer esto en un montón de lugares, solo use un bucle for-key-value si esta es una operación de una sola vez.

<?php

function reindex(&$item, $key, &$reindexedarr) {
    $reindexedarr[$key+1] = $item;
}

$arr = Array (2 => 'c', 1 => 'b', 0 => 'a');

sort($arr);
$newarr = Array();
array_walk($arr, reindex, &$newarr);
$arr = $newarr;
print_r($arr); // Array ( [1] => a [2] => b [3] => c )

?>
monowerker
fuente
-10

Si está bien hacer una nueva matriz, es esto:

$result = array();
foreach ( $array as $key => $val )
    $result[ $key+1 ] = $val;

Si necesita una inversión en el lugar, debe correr hacia atrás para no pisar los índices que necesita:

for ( $k = count($array) ; $k-- > 0 ; )
    $result[ $k+1 ] = $result[ $k ];
unset( $array[0] );   // remove the "zero" element
Jason Cohen
fuente
20
Cualquier respuesta a este problema no debería necesitar un bucle. La parte clave de la respuesta es usar array_values()para obtener una matriz basada en 0 y luego hacer algunos ajustes a ese resultado si realmente se requiere una matriz basada en 1 .
grantwparks