Undesired reordering of keys in PHP array - php

I have a quick question. When building an associative array key casting rules mean that strings containing valid integers 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.) See for example: http://php.net/manual/en/language.types.array.php
The problem I have is that my keys are mixed integer and string .. meaning that when the associative array is built, all keys are reordered with numerical keys appear first before string. This is a sample of what I get in my console log:
...
2032: "9371.84"
2033: "9351.60"
2034: "9331.36"
2035: "9311.12"
ID: "1"
Misc1: "Russian Federation - Conventional"
Misc2: "RUS.Con1"
Misc3: "4"
Misc4: ""
... etc.
How can I avoid this issue, so that the associative array does not re-order my keys?
As an FYI, this is how I generate my array in PHP:
while ($array = mysqli_fetch_assoc($result)) {
$experiment[] = $array;
};
Thank you for your time,
G.

Adding an index to an array in PHP like this:
$array[] = ['another array'];
Will increment the indexes.
You can however specify a string for the key, or cast the integers to strings.

The workaround for the issue I have found is to avoid the associative array structure. This is what my loop looks like now:
while ($array = mysqli_fetch_assoc($result)) {
$experiment[0] = array_keys($array);
$experiment[] = array_values($array);
};
The annoying thing is that $experiment[0] = array_keys($array); gets looped uneccessarily... but at least I get the result that I am looking for and the keys are not cast and re-ordered by the associative array.
If anybody knows how to avoid the unecessary looping for $experiment[0], then please let me know :-)

Related

How to find matching values in multidimentional arrays in PHP

I am wondering if anyone could possibly help?....I am trying to find the matching values in two multidimensional arrays (if any) and also return a boolean if matches exist or not. I got this working with 1D arrays, but I keep getting an array to string conversion error for $result = array_intersect($array1, $array2); and echo "$result [0]"; when I try it with 2d arrays.
// matching values in two 2d arrays?
$array1 = array (array ('A8'), array (9,6,3,4));
$array2 = array (array ('A14'), array (9, 6, 7,8));
$result = array_intersect($array1, $array2);
if ($result){
$match = true;
echo "$result [0]";
}
else{
$match = false;
}
if ($match === true){
//Do something
}
else {
//do something else
}
The PHP documentation for array_intersect states:
Note: Two elements are considered equal if and only if (string) $elem1 === (string) $elem2. In words: when the string representation is the same.
So, the array to string conversion notice is occurring when PHP attempts to compare the array elements. In spite of the notice, PHP will actually convert each of the sub-arrays to a string. It is the string "Array". This means that because
array_intersect() returns an array containing all the values of array1 that are present in all the arguments.
you will end up with a $result containing every element in $array1, and a lot of notices.
How to fix this depends on exactly where/how you want to find matches.
If you just want to match any value anywhere in either of the arrays, you can just flatten them both into 1D arrays, and compare those with array_intersect.
array_walk_recursive($array1, function ($val) use (&$flat1) {
$flat1[] = $val;
});
array_walk_recursive($array2, function ($val) use (&$flat2) {
$flat2[] = $val;
});
$result = array_intersect($flat1, $flat2);
If the location of the matches in the arrays is important, the comparison will obviously need be more complex.
This error(PHP error: Array to string conversion) was caused by array_intersect($array1, $array2), cause this function will compare every single element of the two arrays.
In your situation, it will consider the comparison as this: (string)array ('A8') == (string)array ('A14'). But there isn't toString() method in array, so it will incur the error.
So, if you want to find the matching values in two multidimensional arrays, you must define your own function to find it.

Can Indexed Arrays be used as associative arrays?

I know that in PHP an indexed array that looks like:
$array = ("hello", "world")
is the same as an associative array that looks like:
$array = (0 => "hello", 1 => "world");
so my question is if code like this is valid :
$hello = $array[$array["hello"]];
my thinking is that it translates to
$hello = $array[0]
, which will equal
$hello = "hello"
. In other words, will
$array["hello"]
equal 0?
No, you cannot fetch a key of some array element by its value right away... unless you switch keys and values with array_flip:
$arr = array('hello', 'world');
$arr = array_flip($arr);
print $arr['hello']; // 0
Let's walk through the thinking:
$array = ("hello", "world") // This is implicitly indexed by integer.
is the same as:
$array = (0 => "hello", 1 => "world"); // Explicit indexing.
You can verify by doing print_r($array); In either case, the output would show an indexed array. PHP arrays are all associative. Even if you did not specify a key, the values in an array are ordered by integer index numbers.
Now let's take a look at:
so my question is if code like this is valid :
$hello = $array[$array["hello"]];
This is where the code will break. Why?
$array["hello"] is not a valid value. What this is referencing is "the value of the array's list at index "hello".
However, array("hello", "world") does not have an index key of "hello". Rather, it has a value "hello" which has implicitly the key index 0.
Make sure to read up on PHP arrays and understand that:
PHP arrays are all associative; keys can be strings, or if not explicitly set, will be integers.
Associative arrays are in the form of key => value pairs. If you have a key, you can find the value associated with it.
When trying to get a value from a PHP array, the syntax is: $array['key'] or in the case of multidimensionals $array['firstlevelkey']['secondlevelkey'] etc. The value that gets returned would be the value of the key => value pair at that particular key.
I hope this is helpful!
No, since "hello" is not a valid key in $array.
You can check if a key exist using array_key_exists(key,*array*)

json in perl deserialization length count doesn't work

How do iterate through a deserialized json string? I can't get the right number of values right now it doesn't count right.
my $list = request("http://localhost/getjson.php");
my $deserialize = from_json( $list );
print Dumper($deserialize);
$VAR1 = [
'ab',
'cc',
'de',
'aer',
'ffe',
'cer',
'dad',
'efef',
'afaf',
'ege',
'grsc',
'cegg',
'cegg',
'cegg/aaa.html',
'eggt',
'ttt'
];
print length($deserialize);
13 ?? it should say 16
You are getting back an array reference not an array. You need to dereference the value.
my #array = #$deserialize; # or #{ $deserialize }
print scalar #array;
Moreover, if you want to iterate over the array you can just use for
for (#$deserialize) {
# do stuff
You are actually working with reference to the results. Since JSON can contain all sorts of different results, decode_json won't return a list specifically.
So you need to dereference the variable that you have: $deserialize
Additionally, you don't really want to be using the length function. If you print the integer value (or scalar value) of an array, it will return it's size.
So here's what you want:
my $list = request("http://localhost/getjson.php");
my $deserialize = from_json( $list );
print scalar (#{$deserialize});
That will print the size of the array.
If you want to just start by working with an array you can do:
my $list = request("http://localhost/getjson.php");
my $deserialize = from_json( $list );
my #json_array = #{$deserialize});
print scalar (#json_array);
From perldoc -f length:
This function cannot be used on an entire array or hash to find
out how many elements these have. For that, use "scalar
#array" and "scalar keys %hash", respectively.
You cannot use length to find out the size of an array. To do that, use the advice above.
Your bug gives you a false value because you are taking the length of the array reference, which in string context will be something like ARRAY(0x22d0a88), which in your case seemed to be 13 characters long. E.g. the equivalent of:
print length "ARRAY(0x22d0a88)";
As a curious side note, if you would do length(#array), it will actually return the length of the length of the array. E.g. an array of size 16 would return 2, because the string "16" is two characters long.

associative to numeric array in PHP

I have an associative array, which keys I want to use in numbers. What I mean: The array is kinda like this:
$countries = array
"AD" => array("AND", "Andorra"),
"BG" => array("BGR", "Bulgaria")
);
Obviously AD is 0 and BG is 1, but when I print $countries[1] it doesn't display even "Array".
When I print $countries[1][0] it also doesn't display anything. I have the number of the key, but I shouldn't use the associative key.
Perfect use case for array_values:
$countries = array_values($countries);
Then you can retrieve the values by their index:
$countries[0][0]; // "AND"
$countries[0][1]; // "Andorra"
$countries[1][0]; // "BGR"
$countries[1][1]; // "Bulgaria"
array_keys() will give you the array's keys. array_values() will give you the array's values. Both will be indexed numerically.
you might convert it into a numeric array:
$countries = array(
"AD" => array("AND", "Andorra"),
"BG" => array("BGR", "Bulgaria")
);
$con=array();
$i=0;
foreach($countries as $key => $value){
$con[$i]=$value;
$i++;
}
echo $con[1][1];
//the result is Bulgaria
There are a couple of workarounds to get what you want. Besides crafting a secondary key-map array, injecting references, or an ArrayAccess abomination that holds numeric and associative keys at the same time, you could also use this:
print current(array_slice( current(array_slice($countries, 1)), 0));
That's the fugly workaround to $countries[1][0]. Note that array keys appear to appear in the same order still; bemusing.

Knowing keys type of array?

is there a command to know if an array has their keys as string or plain int?
Like:
$array1 = array('value1','value2','value3');
checkArr($array1); //> Returns true because there aren't keys as string
And:
$array2 = array('key1'=>'value1','key2'=>'value2','value3');
checkArr($array2); //> Returns false because there are keys as string
Note: I know I can parse all the array to check it.
The "compact" version to test this is:
$allnumeric =
array_sum(array_map("is_numeric", array_keys($array))) == count($array);
#Gumbo's suggestion is 1 letter shorter and could very well be a bit speedier for huge arrays:
count(array_filter(array_keys($array), "is_numeric")) == count($array);
You can use array_keys to obtain the keys for the array and then analyse the resultant array.
look at array_keys() if values are int - you got ints if strings -> strings
If you want to check the array's keys, it would be probably better to use something like this:
reset($array);
while (($key = key($array)) !== null) {
// check the key, for example:
if (is_string($key)) {
// ...
}
next($array);
}
This will be most performant, as there are no extraneous copies made of variables that you are not going to use.
On the other hand, this way is probably the most readable and makes the intent crystal clear:
$keys = array_keys($array);
foreach($keys as $key) {
// check the key, for example:
if (is_string($key)) {
// ...
}
}
Take your pick.
Important note:
Last time I checked, PHP would not let you have keys which are string representations of integers. For example:
$array = array();
$array["5"] = "foo";
echo $array[5]; // You might think this will not work, but it will
So keep that in mind when you are checking what the types of such keys are: they might have been created as strings, but PHP will have converted them to integers behind the scenes.

Categories