176

I have the following array, which I would like to reindex so the keys are reversed (ideally starting at 1):

Current array (edit: the array actually looks like this):

Array (

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

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

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

)

How it should be:

Array (

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

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

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

)
mickmackusa
  • 43,625
  • 12
  • 83
  • 136
meleyal
  • 32,252
  • 24
  • 73
  • 79

12 Answers12

500

If you want to re-index starting to zero, simply do the following:

$iZero = array_values($arr);

If you need it to start at one, then use the following:

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

Here are the manual pages for the functions used:

Andrew Moore
  • 93,497
  • 30
  • 163
  • 175
  • 1
    You should use range(0, count($arr) - 1) so you get a zero-indexed array. – Max Hartshorn Aug 10 '15 at 14:54
  • It's great, alternatively you can try using array_unshift($arr,'') to add a zero-indexed element, then unset($arr[0]) to remove it, thus moving all indexes up by one. It maybe quicker than array_combine(). Or not :) – Steve Horvath Oct 02 '18 at 04:37
  • Note that `array_values` returns a copy of the array. So if you have references to the array then `array_splice` would be better. See @imagiro solution. – Nux Aug 01 '19 at 13:09
  • 2
    @MaxHartshorn that is not what this question is asking! – mickmackusa Nov 25 '20 at 20:43
11

Why reindexing? Just add 1 to the index:

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

Edit   After the question has been clarified: You could use the array_values to reset the index starting at 0. Then you could use the algorithm above if you just want printed elements to start at 1.

Gumbo
  • 643,351
  • 109
  • 780
  • 844
9

You can reindex an array so the new array starts with an index of 1 like this;

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

$arr1 = array_values($arr);   // Reindex the array starting from zero*.
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);

The output from the above is;

Array
(
    [2] => red
    [1] => green
    [0] => blue
)
Array
(
    [1] => red
    [2] => green
    [3] => blue
)

*N.B. If all the the input keys are numeric then the array_values() command is not needed. Since PHP 4.3 array_unshift() reindexes numeric keys of the the passed-in array.

Nigel Alderton
  • 2,265
  • 2
  • 24
  • 55
  • @mickmackusa The `array_values()` call is necessary. It reindexes the array starting at zero. – Nigel Alderton Mar 07 '23 at 23:04
  • @mickmackusa `array_unshift()` only reindexes numeric keys. But yes you are correct if all the keys are numeric, then `array_values()` is not necessary. (The question is slightly ambiguous because the question title is different to the question content.) – Nigel Alderton Mar 10 '23 at 18:48
7

This will do what you want:

<?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
  • 316,276
  • 54
  • 369
  • 333
7

You may want to consider why you want to use a 1-based array at all. Zero-based arrays (when using non-associative arrays) are pretty standard, and if you're wanting to output to a UI, most would handle the solution by just increasing the integer upon output to the UI.

Think about consistency—both in your application and in the code you work with—when thinking about 1-based indexers for arrays.

Michael Trausch
  • 3,187
  • 1
  • 21
  • 29
  • 3
    This directly correlates to the separation between the business layer and presentation layer. If you are modifying code in your logic to accommodate presentation, you are doing bad things. For example, if you did this for a controller, suddenly your controller is tied to a specific view renderer rather preparing data for whatever view renderer it may utilize (php, json, xml, rss, etc.) – Tres Apr 13 '11 at 23:46
6

A more elegant solution:

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

6

Well, I would like to think that for whatever your end goal is, you wouldn't actually need to modify the array to be 1-based as opposed to 0-based, but could instead handle it at iteration time like Gumbo posted.

However, to answer your question, this function should convert any array into a 1-based version

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

EDIT

Here's a more reusable/flexible function, should you desire it

$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
  • 105,256
  • 31
  • 182
  • 206
6

The fastest way I can think of

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

And if you just want to reindex the array(start at zero) and you have PHP +7.3 you can do it this way

array_unshift($arr);

I believe array_unshift is better than array_values as the former does not create a copy of the array.

Changelog

Version Description
7.3.0 This function can now be called with only one parameter. Formerly, at least two parameters have been required.

-- https://www.php.net/manual/en/function.array-unshift.php#refsect1-function.array-unshift-changelog

Arleigh Hix
  • 9,990
  • 1
  • 14
  • 31
Rain
  • 3,416
  • 3
  • 24
  • 40
  • My mistake. It was a flawed test. https://3v4l.org/cetL8 `array_unshift()` with only one parameter adds nothing. – mickmackusa Aug 03 '22 at 09:22
3

If you are not trying to reorder the array you can just do:

$array = array_reverse( $array );

and then call it once more to get it back to the same order:

$array = array_reverse( $array );

array_reverse() reindexes as it reverses. Someone else showed me this a long time ago. So I can't take credit for coming up with it. But it is very simple and fast.

The result is an array with indexed keys starting from 0. https://3v4l.org/iQgVh

array (
  0 => 
  (object) array(
     'title' => 'Section',
     'linked' => 1,
  ),
  1 => 
  (object) array(
     'title' => 'Sub-Section',
     'linked' => 1,
  ),
  2 => 
  (object) array(
     'title' => 'Sub-Sub-Section',
     'linked' => NULL,
  ),
)
Dharman
  • 30,962
  • 25
  • 85
  • 135
Mark
  • 55
  • 2
  • 1
    This question is not asking for an indexed array from 0; this question is asking for sequential keys starting from 1. This answer does not provide the desired output. https://3v4l.org/f6Pa4 – mickmackusa Aug 02 '22 at 21:11
3
$tmp = array();
foreach (array_values($array) as $key => $value) {
    $tmp[$key+1] = $value;
}
$array = $tmp;
Tom Haigh
  • 57,217
  • 21
  • 114
  • 142
3

It feels like all of the array_combine() answers are all copying the same "mistake" (the unnecessary call of array_values()).

array_combine() ignores the keys of both parameters that it receives.

Code: (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));

Output:

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
  • 43,625
  • 12
  • 83
  • 136
1

Here's my own implementation. Keys in the input array will be renumbered with incrementing keys starting from $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);
}
mhadidg
  • 1,503
  • 17
  • 29