There is many - good and less good - ways to check associative arrays, but how would you check a "fully associative" array?
$john = array('name' => 'john', , 8 => 'eight', 'children' => array('fred', 'jane'));
$mary1 = array('name' => 'mary', 0 => 'zero', 'children' => array('jane'));
$mary2 = array('name' => 'mary', 'zero', 'children' => array('jane'));
Here $john is fully associative, $mary1 and $mary2 are not.
To make it short, you can't because every array is implemented the same way. From the docs:
An array in PHP is actually an ordered map. A map is a type that associates values to keys.
If have no insight in the implementation, but I'm pretty sure that array(1,2,3) is just shorthand for array(0=>1, 1=>2, 2=>3), i.e. in the end it is exactly the same. There is nothing with which you could distinguish that.
You could only assume that arrays created via array(value, value,...) have an index with 0 and the others have not. But you have already seen that this must not always be the case.
And every attempt to detect an "associative" array would fail at some point.
The actual question is: Why do you need this?
Is this what you're looking for?
<?php
function is_assoc( $array ) {
if( !is_array( $array ) || array_keys( $array ) == range( 0, count( $array ) - 1 ) ) {
return( false );
}
foreach( $array as $value ) {
if( is_array( $value ) && !is_assoc( $value ) ) {
return( false );
}
}
return( true );
}
?>
The detection depends on your definition of associative. This function checks for the associative that means arrays that don't have sequential numeric keys. Some may say that associative is anything where the key was implicitly set instead of calculated by php. Others may even define all PHP arrays as associative (in which case is_array() would have sufficed). Again, it all depends, but this is the function I use in my projects. Hopefully, it's good enough for you.
Related
I know how to get all array keys starting with a particular string in a single array >> How to get all keys from a array that start with a certain string?
But what would be the way to go for multidimensional arrays?
For instance, how to find all keys starting with 'foo-' in:
$arr = array('first-key' => 'first value'.
'sceond-key' => 'second value',
array('foo-1' => 'val',
'bar'=> 'value',
'foo-2' => 'val2')
);
Many thanks, Louis.
You can still apply the solution from the linked question, but with an additional outer filter.
$outputArray = array_filter(
$inputArray,
function ($element) {
return ! is_array($element)
|| ! empty(
array_filter($element, function($key) {
return strpos($key, 'foo-') === 0;
}, ARRAY_FILTER_USE_KEY)
);
}
);
See https://3v4l.org/NsgpR for working code.
PHP Manual: is_array()
I wrote this function to get a subset of an array. Does php have a built in function for this. I can't find one in the docs. Seems like a waste if I'm reinventing the wheel.
function array_subset($array, $keys) {
$result = array();
foreach($keys as $key){
$result[$key] = $array[$key];
}
return $result;
}
I always want this too. Like a PHP version of Underscore's pick.
It's ugly and counter-intuitive, but what I sometimes do is this (I think this may be what prodigitalson was getting at):
$a = ['foo'=>'bar', 'zam'=>'baz', 'zoo'=>'doo'];
// Extract foo and zoo but not zam
print_r(array_intersect_key($a, array_flip(['foo', 'zoo'])));
/*
Array
(
[foo] => bar
[zoo] => doo
)
*/
array_intersect_key returns all the elements of the first argument whose keys are present in the 2nd argument (and all subsequent arguments, if any). But, since it compares keys to keys, I use array_flip for convenience. I could also have just used ['foo' => null, 'zoo' => null] but that's even uglier.
array_diff_key and array_intersect_key are probably what you want.
There is no direct function I think in PHP to get a subset from an array1 with compare to another array2 where the values are the list of key name which we fetch.
Like: array_only($array1, 'field1','field2');
But this way can be achieved the same.
<?php
$associative_array = ['firstname' => 'John', 'lastname' => 'Smith', 'DOB' => '2000-10-10', 'country' => 'Ireland' ];
$subset = array_intersect_key( $associative_array, array_flip( [ 'lastname', 'country' ] ) );
print_r( $subset );
// Outputs...
// Array ( [lastname] => Smith [country] => Ireland );
I'm trying to understand arrays better. Pardon my elementary questions as I just opened my first php book three weeks ago.
I get that you can retrieve key/value pairs using a foreach (or for loop) as below.
$stockprices= array("Google"=>"800", "Apple"=>"400", "Microsoft"=>"4", "RIM"=>"15", "Facebook"=>"30");
foreach ($stockprices as $key =>$price)
What I get confused about are multi dimensional arrays like this one:
$states=(array([0]=>array("capital"=> "Sacramento", "joined_union"=>1850, "population_rank"=> 1),
[1]=>array("capital"=> "Austin", "joined_union"=>1845,"population_rank"=> 2),
[2]=>array("capital"=> "Boston", "joined_union"=>1788,"population_rank"=> 14)
));
My first question is really basic: I know that "capital', "joined_union", "population_rank" are keys and "Sacramento", "1850", "1" are values (correct?). But what do you call [0][1][2]? Are they "main keys" and "capital" etc. sub-keys? I can't find any definition for those; neither in books nor online.
The main question is how do I retrieve Arrays [0][1][2]? Say I want to get the array that joined_union in 1845 (or even trickier during the 1800s), then remove that array.
Finally, can I name Arrays [0][1][2] as California, Texas and Massachusetts correspondingly?
$states=(array("California"=>array("capital"=> "Sacramento", "joined_union"=>1850, "population_rank"=> 1),
"Texas"=>array("capital"=> "Austin", "joined_union"=>1845,"population_rank"=> 2),
"Massachusetts"=>array("capital"=> "Boston", "joined_union"=>1788,"population_rank"=> 14)
));
Unlike other languages, arrays in PHP can use numeric or string keys. You choose.
(This is not a well loved feature of PHP and other languages sneer!)
$states = array(
"California" => array(
"capital" => "Sacramento",
"joined_union" => 1850,
"population_rank" => 1
),
"Texas" => array(
"capital" => "Austin",
"joined_union" => 1845,
"population_rank" => 2
),
"Massachusetts" => array(
"capital" => "Boston",
"joined_union" => 1788,
"population_rank" => 14
)
);
As for querying the structure you have, there are two ways
1) Looping
$joined1850_loop = array();
foreach( $states as $stateName => $stateData ) {
if( $stateData['joined_union'] == 1850 ) {
$joined1850_loop[$stateName] = $stateData;
}
}
print_r( $joined1850_loop );
/*
Array
(
[California] => Array
(
[capital] => Sacramento
[joined_union] => 1850
[population_rank] => 1
)
)
*/
2) Using the array_filter function:
$joined1850 = array_filter(
$states,
function( $state ) {
return $state['joined_union'] == 1850;
}
);
print_r( $joined1850 );
/*
Array
(
[California] => Array
(
[capital] => Sacramento
[joined_union] => 1850
[population_rank] => 1
)
)
*/
-
$joined1800s = array_filter(
$states,
function ( $state ){
return $state['joined_union'] >= 1800 && $state['joined_union'] < 1900;
}
);
print_r( $joined1800s );
/*
Array
(
[California] => Array
(
[capital] => Sacramento
[joined_union] => 1850
[population_rank] => 1
)
[Texas] => Array
(
[capital] => Austin
[joined_union] => 1845
[population_rank] => 2
)
)
*/
1: Multidimensional arrays are basically 'arrays of arrays'.
So if we look here:
array("0"=>array("capital"=> "Sacramento", "joined_union"=>1850, "population_rank"=> 1)
0 is the key, and the array is the value.
Then, inside the value, you have capital as a key, and Sacramento as a value.
2: For removing arrays: Delete an element from an array
3: State names for keys
Yes, you can change that 0, 1, 2 into state names. They become key-values instead of a numbered array. Which makes it much easier to remove exactly the one you want to remove.
Multidimensional arrays are simply arrays which have arrays as values. Simple or "scalar" types are types likes int, string and bool, they hold one value and one value only. Arrays are a compound type, meaning it's a thing that combines several other things together. An array can contain values of other types, including arrays.
The simplest visualization is probably this longhand:
$array = array('foo' => array('bar' => 'baz'));
$foo = $array['foo']; // $foo is now array('bar' => 'baz')
echo $foo['bar']; // outputs 'baz'
This is just shorthand for the same thing as above:
echo $array['foo']['bar'];
$array['foo'] gives you access to the value array('bar' => 'baz'), ['bar'] on that array gives you the value 'baz'. It doesn't matter whether you assign the intermediate value into a variable or continue directly.
The other way around, here's a demonstration of the concept that multidimensional arrays are just arrays in arrays:
$baz = 'baz';
$bar = array('bar' => $baz);
$array = array('foo' => $bar);
That's all there is to it.
You can call nested arrays in array "sub arrays", though there's no real definition and it's not really necessary to define this, since nested arrays aren't a special case of anything.
You may stumble upon explanations using the terms "two dimensional", "three dimensional" etc. arrays. Do not imagine this as tables and cubes, because it's not accurate and will make your head explode when it goes beyond three dimensions. This "dimensionality" simple refers to the depth of the array, i.e. how many arrays are nested within each other.
I wrote this function to get a subset of an array. Does php have a built in function for this. I can't find one in the docs. Seems like a waste if I'm reinventing the wheel.
function array_subset($array, $keys) {
$result = array();
foreach($keys as $key){
$result[$key] = $array[$key];
}
return $result;
}
I always want this too. Like a PHP version of Underscore's pick.
It's ugly and counter-intuitive, but what I sometimes do is this (I think this may be what prodigitalson was getting at):
$a = ['foo'=>'bar', 'zam'=>'baz', 'zoo'=>'doo'];
// Extract foo and zoo but not zam
print_r(array_intersect_key($a, array_flip(['foo', 'zoo'])));
/*
Array
(
[foo] => bar
[zoo] => doo
)
*/
array_intersect_key returns all the elements of the first argument whose keys are present in the 2nd argument (and all subsequent arguments, if any). But, since it compares keys to keys, I use array_flip for convenience. I could also have just used ['foo' => null, 'zoo' => null] but that's even uglier.
array_diff_key and array_intersect_key are probably what you want.
There is no direct function I think in PHP to get a subset from an array1 with compare to another array2 where the values are the list of key name which we fetch.
Like: array_only($array1, 'field1','field2');
But this way can be achieved the same.
<?php
$associative_array = ['firstname' => 'John', 'lastname' => 'Smith', 'DOB' => '2000-10-10', 'country' => 'Ireland' ];
$subset = array_intersect_key( $associative_array, array_flip( [ 'lastname', 'country' ] ) );
print_r( $subset );
// Outputs...
// Array ( [lastname] => Smith [country] => Ireland );
I have an api listener script which takes in get parameters. But I seem to be having issues when users tend to pass mixed case variable names on the parameters.
For example:
http://mylistenerurl.com?paramName1=Hello¶mname2=World
I need my listener to be flixible in such a way that the variable names will be interpreted case-insensitively or rather still all in lower case like after I process the query string on some function, they are all returned as lower-cased variables:
extract(someFunction($_GET));
process($paramname1, $paramname2);
Can anybody shed some light on this?
*much appreciated. thanks!
This should do the trick:
$array_of_lower_case_strings = array_map( "strtolower", array( "This Will Be ALL lowercase.", ... ) );
So in your case:
$get_with_lowercase_keys = array_combine(
array_map( "strtolower", array_keys( $_GET ) ),
array_values( $_GET )
);
One thing I'll mention is you should be VERY careful with extract as it could be exploited to allow unexpected variables to be injected into your PHP.
Apply to your global variables ($_GET, $_POST) when necessary:
e.g. setLowerCaseVars($_GET); in your case
function setLowerCaseVars(&$global_var) {
foreach ($global_var as $key => &$value) {
if (!isset($global_var[strtolower($key)])) {
$global_var[strtolower($key)] = $value;
}
}
}
Edit: Note that I prefer this to using array_combine because it will not overwrite cases where the lower-case variable is already set.
PHP has had a native function (array_change_key_case()) for this task since version 4.2 to change the case of first level keys. To be perfectly explicit -- this function can be used to convert first level key to uppercase or lower case BUT this is not a recursive function so deeper keys will not be effected.
Code: (Demo)
parse_str('paramName1=Hello¶mname2=World&fOo[bAR][BanG]=boom', $_GET);
var_export($_GET);
echo "\n---\n";
$lower = array_change_key_case($_GET);
var_export($lower);
Output:
array (
'paramName1' => 'Hello',
'paramname2' => 'World',
'fOo' =>
array (
'bAR' =>
array (
'BanG' => 'boom',
),
),
)
---
array (
'paramname1' => 'Hello', # N changed to n
'paramname2' => 'World',
'foo' => # O changed to o
array (
'bAR' => # AR not changed because not a first level key
array (
'BanG' => 'boom', # B and G not changed because not a first level key
),
),
)