In my code, I have generated an associative array with keys as floats, however the PHP documentation states that when they become key's in the array they are SUPPOSED to be cast to integers. Instead, they are being cast to strings (which is actually better for me so I'm not complaining).
The problem is that when I try to access these keys using a float as the key value, it casts only the floats with .5 to integers and creates a new entry in the array. Seems like peculiar behavior.
Example:
var_dump( $array );
Output:
array(9) {
[0] =>
int(0)
[1.25] =>
int(0)
[2.5] =>
int(0)
....}
When I try to access the value 2.5 like so,
array[2.5]++;
a new entry in the array is made at array[2]
However if I try to access the array at array[1.25]++;
I successfully add 1 to the value at key: 1.25
Any ideas?
I would just stick with strings all the time:
$a = array(
'0' => 0,
'1.25' => 0,
'2.5' => 0
);
$a['2.5']++;
echo $a['2.5'] . "\n";
var_dump($a);
Output is:
1
array(3) {
[0]=>
int(0)
["1.25"]=>
int(0)
["2.5"]=>
int(1)
}
Related
Given this simple json object:
{
"100": 0,
"100T": 0
}
How do I decode it to an associate array such that both the keys "100" and "100T" remain as strings. When I use json_decode the "100" is converted to an integer.
Example code:
$json = '{"100":0, "100T":0}';
$array = json_decode($json, true);
var_dump($array);
Gives this output:
array(2) {
[100] =>
int(0)
'100T' =>
int(0)
}
But I want this output instead:
array(2) {
'100' =>
int(0)
'100T' =>
int(0)
}
I'm using PHP version 7.0.25 on Ubuntu 16.04
$array1 = [
'1' => '11',
'b' => 1,
3 => 33,
8 => 8
];
$array2 = [
'1' => '22',
'b' => 2,
3 => 44,
9 => 9
];
$merged = array_merge_recursive($array1, $array2);
and the result is:
array(7) {
[0]=>
string(2) "11"
["b"]=>
array(2) {
[0]=>
int(1)
[1]=>
int(2)
}
[1]=>
int(33)
[2]=>
int(8)
[3]=>
string(2) "22"
[4]=>
int(44)
[5]=>
int(9)
}
so lets take a glance: the only part is the 'b' keys, they are actually works. I dont want to overwrite anything of it but putting them together to an array. Thats good! But then keys the other numeric keys (int or string) are screwed up.
I want to have this as result:
[
'1' => ['11', '22']
'b' => [1, 2]
[3] => [33, 44]
[8] => 8,
[9] => 9
]
possible?
EDIT: of course keys "1" and 1 - string vs int key are the same
Let's break down this question into to separate problems:
When a key in the second array exist in the first array, you want to create an array and make the value the first element of that array.
To be honest, I don't know an easy way of solving this. I'm not sure there is one. And even if, I'm not sure you really want it. Such a function will lead to arrays having values that are a string or an array. How would you handle such an array?
Update: Well, there is one. Your example already shows that array_merge_recursive will convert values with a string key into an array. So 1 => 'foo' would be 0 => 'foo', but 'foo' => 'bar' will end up as 'foo' => ['bar']. I really don't understand this behaviour.
Using string keys would help you out in this case, but after learning more about array_merge_recursive I decided to avoid this function when possible. After I asked this question someone filed it as a bug in it since PHP 7.0, since it works differently in PHP 5.x.
You want to keep the keys, while array_merge_resursive doesn't preserve integer keys, while it does for integer keys:
If the input arrays have the same string keys, then the values for
these keys are merged together into an array, and this is done
recursively, so that if one of the values is an array itself, the
function will merge it with a corresponding entry in another array
too. If, however, the arrays have the same numeric key, the later
value will not overwrite the original value, but will be appended.
To make it worse, it handles differently when handling the nested arrays:
$array1 = [30 => [500 => 'foo', 600 => 'bar']];
$array2 = [];
array_merge_recursive($array1, $array2);
//[0 => [500=> 'foo', 600 => 'bar']];
So effectively, array_merge_resursive isn't really resursive.
Using array_replace_resursive solves that problem:
array_replace_recursive($array1, $array2);
//output:
//array:5 [
// 1 => "22"
// "b" => 2
// 3 => 44
// 8 => 8
// 9 => 9
//]
Please note that PHP is very consistent in being inconsistent. While array_merge_recursive isn't recursive, array_replace_recursive doesn't replace (it also appends):
If the key exists in the second array, and not the first, it will be
created in the first array.
In many cases this is desired behavior and since naming functions isn't PHP's strongest point, you can consider this as a minor issue.
Can you rely on a native function to return your exact desired output? No. At least not in any version as of the date of this post (upto PHP8.1).
The good news is that crafting your own solution is very simple.
Code: (Demo)
foreach ($array2 as $key => $value) {
if (!key_exists($key, $array1)) {
$array1[$key] = $value;
} else {
$array1[$key] = (array)$array1[$key];
$array1[$key][] = $value;
}
}
var_export($array1);
I suppose I am less inclined to recommend this output structure because you have potentially different datatypes on a given level. If you were building subsequent code to iterate this data, you'd need to write conditions on every level to see if the data was iterable -- it just feels like you are setting yourself up for code bloat/convolution. I'd prefer a result which has consistent depth and datatypes.
PHP documentation states that the default value of array_keys second argument is NULL.
However, when passing NULL explicitly, array_keys does not seem to work properly.
Example:
code
$a = array(10=>'a', 11=>'b', 12=>'b', 13=>'c', 14=>'c', 15=>'b');
$keys = array_keys($a);
var_dump($keys); //Output 0
$keys = array_keys($a, null);
var_dump($keys); //Output 1
Output
array
0 => int 10
1 => int 11
2 => int 12
3 => int 13
4 => int 14
5 => int 15
array
empty
Question
I reckon it must be trying to find keys whose value is null.
Passing false or empty string produces the exact same behavior (obviously).
So, what is the default value?
Answer
xdazz answer is right. When inspecting the C code of this function, my first though was that this was a bad implementation at C level (and easily fixed by removing code)
But then I realized this is actually the intended behavior since they went to a lot of trouble to enable you to test for NULL values inside the array.
The default value is hard to explain here.
It is special case, the default value of second parameter is not actually the php's NULL, but the C level's NULL.
Dive into the source code:
PHP_FUNCTION(array_keys)
{
zval *input, /* Input array */
*search_value = NULL, /* Value to search for */
//....
if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "a|zb", &input, &search_value, &strict) == FAILURE) {
return;
}
// ....
You could see, the default value is NULL for search_value, but if you specified the second parameter of array_keys, then after zend_parse_parameters, search_value will not be NULL.
I agree with xdazz. However, it seems that passing 0 works. Don't ask me how, though! (And, YMMV.)
$a = array(10=>'a', 'xaa'=>'b', 12=>'b', 13=>'c', 14=>'c', 15=>'b');
$keys = array_keys($a, 0);
var_dump($keys); //Output 0
Returns:
array(6) { [0]=> int(10) [1]=> string(3) "xaa" [2]=> int(12) [3]=> int(13) [4]=> int(14) [5]=> int(15) }
Since you're searching for null, there's no result to give back to you :)
It is hard to infer from PHP manual as to the use of search_value parameter. I needed to do try an example.
If the optional search_value is specified,
then only the keys for **that** value are returned.
Otherwise, all the keys from the input are returned.
It means that when search_value is specified in array_keys(), the values in the array (not keys) are searched against search_value. If match occurs, the key for that value in search_value is returned.
Example
<?
$foo = array('first' => 'my_first',
'second' => 'my_second',
'third' => 'my_third',
'fourth' => null);
$keys = array_keys($foo);
var_dump($keys); //Output 0
$keys = array_keys($foo, 'my_second');
var_dump($keys); //Output 1
$keys = array_keys($foo, null);
var_dump($keys); //Output 2
?>
Output
0:
array(4) {
[0]=>
string(5) "first"
[1]=>
string(6) "second"
[2]=>
string(5) "third"
[3]=>
string(6) "fourth"
}
1:
array(1) {
[0]=>
string(6) "second"
}
2:
array(1) {
[0]=>
string(6) "fourth"
}
This is such a simple problem but the PHP doc does not explain why it is happening.
I have this code:
var_dump($newattributes); var_dump($oldattributes);
var_dump(array_diff($newattributes, $oldattributes));
For briefity I am going to omit large parts of the structure I am actually using (since each is 117 elements long) and cut to the case.
I have one array called $newattributes which looks like:
array(117){
// Lots of other attributes here
["deleted"] => int(1)
}
And another called $oldattributes which looks like:
array(117){
// Lots of other attributes here
["deleted"] => string(1) "0"
}
Which looks different right? According to array_diff: no. The output I get from array_diff is:
array(0) { }
I have read the documentation page however it says:
Two elements are considered equal if and only if (string) $elem1 ===
(string) $elem2. In words: when the string representation is the same.
And I am not sure how "1" can object equal "0".
So am I seeing some caveat with array_diff I didn't take into consideration?
The problem might reside in the fact that you are using associative arrays : you should try and use the following for associative arrays : array_diff_assoc():
<?php
$newattributes = array(
"deleted" => 1
);
$oldattributes = array(
"deleted" => "0"
);
$result = array_diff_assoc($newattributes, $oldattributes);
var_dump($result);
?>
result :
array(1) {
["deleted"]=>
int(1)
}
It does happen to me too (when there are more values than one)
$new = array('test' => true, 'bla' => 'test' 'deleted' => 1);
$old = array('test' => true, 'deleted' => '0');
For a full array_diff you need to make some extra work, because in default it returns a relative complement
Try this:
array_diff(array_merge($new, $old), array_intersect($new, $old))
Result:
Array
(
[bla] => test
[deleted] => 0
)
I have this kind of array:
$a = array(
'one' => 'one',
'0' => '0',
'two' => 'two',
'three' => 'three',
'four'
);
as you can see it is an associative array BUT not all the keys have the value (take a look at the last).
My question is, how can i loop this kind of array to get key(if exists) and the respective value?
Thank you!
The string 'four' in your example is not a key but a value. The corresponding key will be 1. This happens because PHP converts the string key '0' to numeric key 0 and for the value 'four' it uses the next numeric key which will be 1.
Reference:
A key may be either an integer or a string. If a key is the standard
representation of an integer, it will be interpreted as such (i.e. "8"
will be interpreted as 8, while "08" will be interpreted as "08")
To have a key with no value you can use NULL as the value:
'four' => null
Similarly to have an empty key use null as key:
null => 'four'
And to loop over such an array you can use a foreach loop. To detect if a key/value is null or not you can use the isset function.
With var_dump($a); you see all keys and values:
array(5) {
["one"] => string(3) "one"
[0] => string(1) "0"
["two"] => string(3) "two"
["three"] => string(5) "three"
[1] => string(4) "four"
}
you can use the foreach construction:
foreach($a as $key=>$val){
// $key is a current key
// $val is tha current value associated
}
As described in PHP: Arrays
A key may be either an integer or a string. If a key is the standard representation of an integer, it will be interpreted as such (i.e. "8" will be interpreted as 8, while "08" will be interpreted as "08"). Floats in key are truncated to integer. The indexed and associative array types are the same type in PHP, which can both contain integer and string indices.
So you cannot distinguish key '0' and 0. And your last element is not a key, it is a value with auto incremental integer key 1. You can check with var_dump($a):
array(5) {
["one"]=>
string(3) "one"
[0]=>
string(1) "0"
["two"]=>
string(3) "two"
["three"]=>
string(5) "three"
[1]=>
string(4) "four"
}
If you can ensure all your keys do not start with digit, then you can just iterate the array as usual, and test the key using is_int.