2

Due to serialization/deserialization of arrays I get incorrect data type of array keys in some cases.

$data = [
    0 => 'item 1',
    4 => 'item 2',
    7 => 'item 3',
];

$storage->set( 'demo', $data );

// ...and get it back later

$data = storage->get( 'demo' );
var_dump( $data );

/*
Result:

    array (size=3)
    "0" => string "item 1"
    "4" => string "item 2"
    "7" => string "item 3"

But I need (keys must be int):

    array (size=3)
    0 => string "item 1"
    4 => string "item 2"
    7 => string "item 3"
*/

Question: Is there an easy way to convert the keys back to integer?

I tried array_reverse( array_map( 'intval', array_reverse( $data ) ) ) but this loses items with different keys but identical values and most importantly it has problems with non-numeric keys.

Also array_values( $data ) did not solve the problem due to similar problems: It loses non-numeric keys and also keys are not sequential (it can be 0, 4, 7, but array_values() will assign keys 0, 1, 2)


Update - why this is important for my

We had problems with some website configuration because of this:

  • $data['0'] returns 'item1' but
  • $data[0] returns null
6
  • Use a foreach. Though I can't imagine situation why you need this. Commented Aug 4, 2017 at 10:28
  • 1
    Why do you need integers ? That would be useful information in order to help you. Commented Aug 4, 2017 at 10:30
  • 1
    Isn't something fishy going on here, because string keys that are valid ints are cast to int see doc : Additionally the following key casts will occur: Strings containing valid decimal integers, unless the number is preceded by a + sign, will be cast to the integer type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer. Commented Aug 4, 2017 at 11:04
  • Agree with the others here, why? If the key is string and you echo $arr[1] as int it will still find the correct key. There is in my opinion no need to change from string to int on keys Commented Aug 4, 2017 at 11:24
  • As @Andreas said: why do you want to get back the keys in integer? Commented Aug 4, 2017 at 11:27

4 Answers 4

3

Propably simplest solution:

$keys = array_keys($data);
$values = array_values($data);

$intKeys = array_map('intval', $keys);

$newData = array_combine($intKeys, $values);

Update:
With checking of key type:

$keys = array_keys($data);
if ($keys === array_filter($keys, 'is_numeric')) {

    $data = array_combine(
        array_map('intval', $keys),
        array_values($data)
    );    
}
Sign up to request clarification or add additional context in comments.

8 Comments

Did you read any comment at all on this page before posting this?
But with your example not even string keys work. sandbox.onlinephpfunctions.com/code/…
@Andreas yes, and that's why he need to convert string keys to integers :)
@Andreas and also in PHP7 it can be used declare(strict_types=1); and then string array keys may cause fatal errors.
Actually this is a very good approach! I've used most of this code, but added an additional check to see if all keys are numeric: if (array_reduce( array_keys( $arr ), function( $res, $val ) { return $res && is_numeric( $val ); }, true )) {...}
|
2

PHP documentation

Additionally the following key casts will occur:

Strings containing valid decimal ints, unless the number is preceded by a + sign, will be cast to the int type. E.g. the key "8" will actually be stored under 8. On the other hand "08" will not be cast, as it isn't a valid decimal integer.

So you can use it, you don't need to check any conditions

Comments

1

You can use is_numeric and intval to convert the keys:

$data2 = array();
foreach($data as $key=>$value) {
    $key2 = is_numeric($key) ? intval($key) : $key;
    $data2[$key2] = $value;
}

var_dump( $data2 );

2 Comments

I see what you mean. The comment of Zimmi means I cannot really test my code because arrays with string integer keys do not happen normally.
You can force them, but again I'm quite sure it will work. Php are good with understanding small "errors"
0

Thanks to this great suggestion https://stackoverflow.com/a/45505894/313501 I came up with this code:

// Convert array keys to integer values, if array only contains numeric keys.
$is_numeric = array_reduce(
    array_keys( $data ),
    function( $res, $val ) { return $res && is_numeric( $val ); },
    true
);
if ( $is_numeric ) {
    $data = array_combine(
        array_map( 'intval', array_keys( $data ) ),
        array_values( $data )
    );
}

2 Comments

As a general rule, it's more advisable to fix the cause of the problem instead of fixing the symptoms. As per your comment below jkucharovic's answer, the array with string keys comes from (array) json_decode(). You should use json_decode($string, true), which will return an associative array with keys as ints, instead of a stdClass instance with properties as strings.
@Philipp use array_filter instead of array_reduce – see my updated answer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.