Como você reindexa uma matriz em PHP?

157

Eu tenho a seguinte matriz, que eu gostaria de reindexar para que as chaves sejam revertidas (idealmente começando em 1):

Matriz atual ( edit: a matriz realmente se parece com isso):

Array (

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

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

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

)

Como deve ser:

Array (

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

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

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

)
meleyal
fonte
1
Onde há algo invertido?
Gumbo
Ver a minha edição para o primeiro exemplo
meleyal
E por que você precisa que o índice do primeiro elemento seja 1? Apenas uma questão de formato ou para processamento interno?
Gumbo
Ele será usado como um parâmetro para uma função para obter o um segmento url, algo como get_url_segment (1) retornaria por exemplo, sobre esta página "perguntas"
meleyal

Respostas:

445

Se você deseja voltar a indexar o zero, basta fazer o seguinte:

$iZero = array_values($arr);

Se você precisar iniciar um, use o seguinte:

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

Aqui estão as páginas de manual para as funções usadas:

Andrew Moore
fonte
1
Você deve usar o intervalo (0, count ($ arr) - 1) para obter um array com índice zero.
Max Hartshorn
É ótimo, como alternativa, você pode tentar usar array_unshift ($ arr, '') para adicionar um elemento indexado a zero e desabilitar ($ arr [0]) para removê-lo, movendo todos os índices para cima um por um. Talvez seja mais rápido que array_combine (). Ou não :) #
911 Steve Horvath
Observe que array_valuesretorna uma cópia da matriz. Portanto, se você tiver referências à matriz, array_spliceseria melhor. Veja a solução @imagiro.
Nux
Apenas array_values()fazê-la funcionar, se você começar com índice 0 o tempo todo.
kishor10d
55

Aqui está a melhor maneira :

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

que retorna

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

fazendo isso

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

você entende isso

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

Explicação

array_values() : Retorna os valores da matriz de entrada e os índices numericamente.

array_filter(): Filtra os elementos de uma matriz com uma função definida pelo usuário (UDF Se nenhuma for fornecida , todas as entradas na tabela de entrada com o valor de FALSE serão excluídas .)

Sandra
fonte
3
Se você não se importa com a ordem, também pode classificar ($ array);
Peter M. Elias
array_filter()parece completamente irrelevante para os dados da amostra.
mickmackusa
13

Acabei de descobrir que você também pode fazer uma

array_splice($ar, 0, 0);

Isso faz a reindexação no local, para que você não termine com uma cópia da matriz original.

imagiro
fonte
9

Por que reindexar? Basta adicionar 1 ao índice:

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

Editar    Depois que a pergunta for esclarecida: Você pode usar o array_valuespara redefinir o índice iniciando em 0. Em seguida, você pode usar o algoritmo acima se desejar que os elementos impressos comecem em 1.

quiabo
fonte
resposta subestimado a esta pergunta :)
jminkler
6

Bem, eu gostaria de pensar que, para qualquer que seja seu objetivo final, você não precisaria modificar a matriz para ser baseada em 1 e não em 0, mas poderia lidar com isso no momento da iteração, como o Gumbo postou.

No entanto , para responder sua pergunta, essa função deve converter qualquer matriz em uma versão baseada em 1

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

EDITAR

Aqui está uma função mais reutilizável / flexível, se você desejar

$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
fonte
5

Isso fará o que você deseja:

<?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
fonte
5

Você pode considerar por que deseja usar uma matriz baseada em 1. Matrizes baseadas em zero (ao usar matrizes não associativas) são bastante padrão e, se você deseja gerar uma saída para uma interface do usuário, a maioria lidaria com a solução apenas aumentando o número inteiro na saída da interface do usuário.

Pense na consistência - tanto no aplicativo quanto no código com o qual trabalha - ao pensar nos indexadores baseados em 1 para matrizes.

Michael Trausch
fonte
2
Isso se correlaciona diretamente com a separação entre a camada de negócios e a de apresentação. Se você está modificando o código em sua lógica para acomodar a apresentação, está fazendo coisas ruins. Por exemplo, se você fez isso para um controlador, de repente, seu controlador está ligado a um renderizador de vista específico e preparação de dados para qualquer que seja vista renderizador pode utilizar (php, json, xml, rss, etc.)
Tres
5

Uma solução mais elegante:

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

Ionuţ Pleşca
fonte
6
Você chama isso de elegante?
Julian
5

Você pode reindexar uma matriz para que a nova matriz comece com um í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);

A saída acima é;

Array
(
    [2] => red
    [1] => green
    [0] => blue
)
Array
(
    [1] => red
    [2] => green
    [3] => blue
)
Nigel Alderton
fonte
Você não precisa usar array_valuesaqui. Veja minha resposta.
Rain
4

Semelhante ao @monowerker, eu precisava reindexar uma matriz usando a chave de um 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);

Isso resultou em:

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
        )
)
usuario
fonte
3
$tmp = array();
foreach (array_values($array) as $key => $value) {
    $tmp[$key+1] = $value;
}
$array = $tmp;
Tom Haigh
fonte
3

Se você não está tentando reordenar a matriz, basta:

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

O array_reverse é muito rápido e é reordenado à medida que se inverte. Alguém me mostrou isso há muito tempo. Portanto, não posso receber crédito por ter vindo com isso. Mas é muito simples e rápido.

Marca
fonte
2

Semelhante à contribuição de Nick, cheguei à mesma solução para reindexar uma matriz, mas aprimorei a função um pouco desde a versão 5.4 do PHP, que não funciona devido à passagem de variáveis ​​por referência. Exemplo de função de reindexação é assim usando o usefechamento de palavras-chave:

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

Aqui está minha própria implementação. As chaves na matriz de entrada serão renumeradas com o incremento de chaves 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
fonte
1

Simplesmente faça o seguinte:

<?php

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

Você pode fazer isso facilmente depois de usar as funções array_values ​​() e array_filter () juntas para remover os elementos vazios da matriz e reindexá-la de uma matriz no PHP.

Função array_filter () A função PHP array_filter () remove elementos ou valores vazios da matriz de uma matriz no PHP. Isso também removerá valores em branco, nulos, falsos, 0 (zero).

Função array_values ​​() A função PHP array_values ​​() retorna uma matriz contendo todos os valores de uma matriz. A matriz retornada terá teclas numéricas, iniciando em 0 e aumentando em 1.

Remover elementos vazios da matriz e reindexar

Primeiro vamos ver a saída do array $ stack:

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

Resultado:

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

Na saída acima, queremos remover valores em branco, nulos, 0 (zero) e, em seguida, reindexar os elementos da matriz. Agora vamos usar as funções array_values ​​() e array_filter () juntas, como no exemplo abaixo:

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

Resultado:

Array
(
    [0] => PHP
    [1] => HTML
    [2] => CSS
    [3] => JavaScript
)
Estrela
fonte
array_filter()parece completamente irrelevante para os dados da amostra do OP.
mickmackusa
1

Remoção duplicada e reindexar uma 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
fonte
array_filter()parece completamente irrelevante para os dados da amostra do OP.
mickmackusa
1

A maneira mais rápida que consigo pensar

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

E se você quiser apenas reindexar a matriz (comece em zero) e tiver o PHP +7.3, poderá fazê-lo desta maneira

array_unshift($arr);

Eu acredito que array_unshifté melhor do que array_valuescomo o primeiro não cria uma cópia da matriz.

Chuva
fonte
0

Parece que todas as array_combine()respostas estão copiando o mesmo "erro" (a chamada desnecessária de array_values()).

array_combine() ignora as chaves dos dois parâmetros que recebe.

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

Resultado:

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
fonte
0

A ordenação é apenas uma ordenação () , a reindexação parece um pouco boba, mas se for necessário, isso será feito. Embora não esteja no local. Use array_walk () se você fizer isso em vários lugares, apenas use um loop for-key-value se esta for uma operação única.

<?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
fonte
-10

Se não há problema em criar uma nova matriz, é o seguinte:

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

Se você precisar de reversão no local, precisará executar um retrocesso para não pisar nos índices necessários:

for ( $k = count($array) ; $k-- > 0 ; )
    $result[ $k+1 ] = $result[ $k ];
unset( $array[0] );   // remove the "zero" element
Jason Cohen
fonte
20
Qualquer resposta para esse problema não deve precisar de um loop. A parte principal da resposta é usar array_values()para obter uma matriz baseada em 0 e, em seguida, fazer alguns ajustes nesse resultado, se uma matriz baseada em 1 for realmente necessária.
Grantwparks