Php if array key is numeric

Jeff-Russ / PHP: numeric array keys.md

Arrays in PHP treat integer and string integers synonymously. If you set $a[‘1’] = ‘1’ and access $a[1] you will get ‘1’ . This is because php juggled your string key to an integer before assigning it; the assigment was actually made to an integer key. PHP also juggles in the process of accesssing too which means if you try to access [1] with [‘1’] it will work. Therefore there is no real distinction between string integers and real integer, you can use them interchangably.

Remember that ‘1.0’ does not equal ‘1’ or 1 with strict comparison. This is true of array keys as well: you can have both [‘1.0’] and [‘1’] and they would be different elements but not [1] and [‘1’] .

$arr = array(0, 1); $arr['0'] = 'changing value of [0] here'; $arr['1.0'] = 'adding a new element at ['1.0]';

Possibly the most troubling behavior in PHP array keys happens when you try to use real floating point numbers as keys.

$arr = array(1=>1); $arr[1.1] pl-s">we just clobbered [1] !!";

Floating point strings are converted to integer key, dropping the decimal component!! This is is pretty good reason to wrap all keys in string when accessing or assigning to be safe since this would retain floats and not effect integers.

Читайте также:  Выполнить javascript во фрейме

Wrapping in strings works but not when you actually want [‘1.0’] to be the same as [1] . Also.

  1. You may not want to have both [‘1’] and [‘1.0’] allowed distinctly.
  2. You may not want to have both [‘1.0’] and [‘1.00’] allowed distinctly. Trailing zeros can pose an issue.
  3. You probably don’t want php to treat [1.5] as if you typed [1] .

If you are making an ArrayObject class you would be able to sanitize numeric keys. You could also do this with normal arrays, wrapping assigment and accessing in functions.

If you add a number to a numeric string you will get either a float or an int depending on whatever would not loose resolution. If you add «1.5» + 0 you will get a float. Converting 1.0 to string will drop the decimal which is what we want.

$var = (string)('1.0' + 0); // $var is '1' $var = (string)('1.5' + 0); // $var is '1.5'

This works rather well to solve all three issues! But If if you have a non-numeric string you would have just mangled you key. You could wrap the above in and if statement:

if ( is_numeric($key) ) < $key = (string)($key + 0); >

This works fine but if you are really obsessed in optimizing your code performance you might want to avoid the call to is_numeric. If you loose compare with == or != the result of above with the original they will be ‘equal’ if the original was a float, int, or numeric string (int or float)!

if ( ($n=(string)($key + 0)) == $k) $key = $n;

Or if you want to reject any non-numerics completely you could do the following and then just use $n and not $key subsequently.

if ( ($n=(string)($key + 0)) != $key) trigger_error('only numeric keys!'); // use $n . 

ksort has different behaivor if you have non-numeric string keys in your array. Without them, it has a very nice characteristic:

$arr = [ '0.0'=>'0.0', 2 => 2, '1' => 1, '3' => 3, 5 => 5, '11' =>'11', '6' => 6, '5.1'=>'5.1', 8 => 8, '9' => 9, '10' => 10, ]; ksort($arr); var_dump($arr);

This results in a nice numeric order, regardless of whether you have a integer, string integer or string float:

array ( '0.0'=> '0.0', 1 => 1, 2 => 2, 3 => 3, 5 => 5, '5.1'=> '5.1', 6 => 6, 8 => 8, 9 => 9, 10 => 10, 11 => '11', )

This could be very useful, unlike the havoc that occurs when you mix in some non-numeric string keys:

$arr = [ '0.0'=>'0.0', 2 => 2, '1' => 1, 'what?'=>'what?', '3' => 3, 5 => 5, 'eight'=>'eight', '11' =>'11', '6' => 6, '5.1'=>'5.1', 8 => 8, '9' => 9, '10' => 10, ];
array ( '0.0' => '0.0', '5.1' => '5.1', 'eight' => 'eight', 'what?' => 'what?', 1 => 1, 2 => 2, 3 => 3, 5 => 5, 6 => 6, 8 => 8, 9 => 9, 10 => 10, 11 => '11', )

Not so nice: it places string numerics (floats, since int strings become ints) first, then alpha strings, then integers. Interesting, all that matters to retain this goodness is that your first character is a numeric:

$arr = [ '0.0'=>'0.0', 2 => 2, '1' => 1, '5.5'=> 5, '3' => 3, 5 => 5, '4:n'=>'4:n', '11' =>'11', '6' => 6, '5.x'=>'5.x', 8 => 8, '9' => 9, '10' => 10, ];
array ( '0.0' => '0.0', 1 => 1, 2 => 2, 3 => 3, '4:n' => '4:n', 5 => 5, '5.5' => 5, '5.x' => '5.x', 6 => 6, 8 => 8, 9 => 9, 10 => 10, 11 => '11', )

This might be handy. You could filter out bad keys with:

if ( ($n=(string)($k+0)) == $k) $k = $n; elseif ($k==='' || !ctype_digit ("$k"[0])) trigger_error('key must start with numeric');

but this would block negative number or explicit positive numbers ( «-1:3» ) So you might want:

if ( ($n=(string)($k+0)) == $k) $k = $n; elseif (!preg_match ('/^[-+]?2.*$/',$k pl-s1">$k")) trigger_error('key must be or start with number');

This is better for another reason: it’s safer since $k=»$k» ensures you are left with a string no matter what, which is also important for avoiding errors with preg_match .

NOTE that the above would convert ‘1.1.0’ or ‘1.1.5’ to ‘1.1’ so this approach might not be suitable for version numbers. This is because those strings DO juggle to numbers, both with +0 and the comparison with == just drop the final dot and number. If you version number style strings you might want to sanitize with:

if (is_numeric($k)): $k = (string)($k+0); elseif ( !preg_match('/^[-+]?1.*$/',$k pl-s1">$k") ): trigger_error("keys must be or start with number"); endif;

Источник

How to check if an (int) array key is set by default or is a custom (int) key?

Instead of first $arr default key 1 i want to set it to 25 and then identify the fact that it was set instead of automatically generated:

$arr = ['item_one', '25' => 'item_two']; 
[0] is not a custom key! [25] is not a custom key! 

2 Answers 2

$arr = ['item_one', '25' => 'item_two']; $i = 0; foreach($arr as $k => $v) < if($i != $k)< echo '[' . $k . '] is a custom key!'; >$i++; > 

@TimMorton Use ! = Can exclude the key 0 and correctly find out that 25 is a custom key in this case, Not all cases should use ! == .

@CalosKao um, this proves that 1 != 25. That doesn’t prove it’s a string (or a so called custom key).

@TimMorton I agree that this snippet cannot prove that the custom key is a string, and that this snippet will not work if the array length exceeds 26.

Aside from some trickery with objects that may or may not work, the only solution I can see is to make duck typing work for you instead of against you:

Prepend a space or 0 in front of the number. It will then be a string in the key » 25″ or «025» , but will convert to an integer if you use it as a number or cast it as an integer elsewhere.

php > $arr = ['item_one', '025' => 'item_two']; php > foreach($arr as $k => $v) < php < if(is_int($k)) < php < echo '['.$k.'] is not a custom key!'; php < >php < >[0] is not a custom key! php > 

Simply comparing the key to the position within the element is not reliable:

php > $arr = ['item_one','25'=>'item_two','2'=>'item_three']; php > $i=0; php > foreach($arr as $k=>$v) < php < if($i != $k) < php < echo '['.$k.'] is a custom key'; php < >php < $i++; php < >[25] is a custom key php > (note: missed $arr['2']) 
  • 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.
  • Floats are also cast to integers, which means that the fractional part will be truncated. E.g. the key 8.7 will actually be stored under 8.
  • Bools are cast to integers, too, i.e. the key true will actually be stored under 1 and the key false under 0. Null will be cast to the empty string, i.e. the key null will actually be stored under «».
  • Arrays and objects can not be used as keys. Doing so will result in a warning: Illegal offset type.

Источник

target numeric keys only in array

I have an array with 2 kinds of keys, strings and integers. I want to do foreach() on this array and want to do it for numeric keys only. What is the most elegant way of doing it?

Did you get this array through mysql_fetch_array by any chance? If so, you can tell it to only return a numeric array.

you will have to iterate the whole array and check if the key is not numeric just do nothing and continue.

thank you, I was thinking there is some magic function in php, but this will do just fine. and sorry for numeric/integer mess.

4 Answers 4

Here’s a complicated method using array_filter() to return the numeric keys then iterate over them.

// $input_array is your original array with numeric and string keys // array_filter() returns an array of the numeric keys // Use an anonymous function if logic beyond a simple built-in filtering function is needed $numerickeys = array_filter(array_keys($input_array), function($k) ); // But in this simple case where the filter function is a plain // built-in function requiring one argument, it can be passed as a string: // Really, this is all that's needed: $numerickeys = array_filter(array_keys($input_array), 'is_int'); foreach ($numerickeys as $key) < // do something with $input_array[$key'] >

It’s much easier though to just foreach over everything:

foreach ($input_array as $key => $val) < if (is_int($key)) < // do stuff >> 

Edit Misread original post and thought I saw «numeric» rather than «integer» keys. Updated to use is_int() rather than is_numeric() .

Источник

PHP check if any array value is not a string or numeric?

I have an array of values and I’d like to check that all values are either string or numeric. What is the most efficient way to do this? Currently I’m just checking for strings so I was just doing if (array_filter($arr, ‘is_string’) === $arr) which seems to be working.

7 Answers 7

Combined with array_filter , you can then compare the two arrays to see if they are equal.

function isStringOrNumeric($in) < // Return true if $in is either a string or numeric return is_string($in) || is_numeric($in); >class Test<> $a = array( 'one', 2, 'three', new Test()); $b = array_filter($a, 'isStringOrNumeric'); if($b === $a) echo('Success!'); else echo('Fail!'); 

Would be great if he needed to have data on each field individually, but quite inefficient when you just need one value for whole array, isn’t it?

My apologies, read the question wrong. I have updated it to use the array_filter, but I still think this solution will iterate through the array twice (but I believe is unavoidable)

I understand the logic of your function, but I think lots of programmers forgot «old ways» to think in procedural way and with sequence approach to things. Take a look at my answer, honestly tell me what don’t you like about it.

I don’t understand your (his) solution, why trying to use array_filter and compare whole array O(2n) when you can have O(n) without any problems. I don’t mean to troll or insult you I just want to understand what’s better on your way and reason why you choose this way (or whether you just wanted to change his code as little as possible).

Источник

Оцените статью