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.
Related
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 );
When gathering statistical data I need to address an array with a varying number of indices.
I have to add to $array[$ind1][$ind2] and to $array[$ind1][$ind2][$ind3][$ind4].
Is it possible to create a function like arrayAdd($number,$arrayOfIndices)
where in the first case $arrayOfIndices is [$ind,$ind2]
and the second case [$ind1,$ind2,$ind3,$ind4]?
I solved my problem to write it all out, depending of count of $arrayOfIndices.
Looking however to a more elegant and generic way.
<?php
function array_add(&$array, array $indices, $value) {
count($indices)==1
? $array[$indices[0]] = $value
: array_add($array[array_shift($indices)], $indices, $value);
}
$data = ['pig'=>'man'];
$indices = ['foo', 'bar', 'baz'];
array_add($data, $indices, 'bat');
var_export($data);
Output:
array (
'pig' => 'man',
'foo' =>
array (
'bar' =>
array (
'baz' => 'bat',
),
),
)
I have an array in PHP, here is a snippet:
$locations = array(
array(
"id" => 202,
"name" => "GXP Club - Fable"
),
array (
"id" => 204,
"name" => "GXP Club - Gray"
)
);
What I know (from a GET) is the ID (202). What I would like to display is
"Showing results for "
( where $locations[?][id] = $_GET['id'] { echo $locations[?][name] } )
- if you will pardon my use of pseudo code.
Not sure what function is best or if I need to loop over the whole array to find that. Thanks.
Edit: for further clarification. I need to learn the [name] given the [id]
foreach( $locations as $arr ) {
if($arr['id'] == $_GET['id']) {
echo $arr['name'];
break;
}
}
That should do the trick.
While looping over the array is the solution for the problem as described, it seems more optimal to change your array to be $id=>$name key-value pairs, instead of named key values if that's all the data in the array, e.g.:
$locations = array( '202' => 'GXP Club - Fable',
'204' => 'GXP Club - Gray',
)
Alternatively, if there's more data, I'd switch to a nested data structure, e.g.:
$locations = array( '202' => array( 'name' => 'GXP Club - Fable', 'prop2' =>$prop2, etc),
'204' => array( 'name' => 'GXP Club - Gray', 'prop2' =>$prop2, etc),
)
That makes it so you can access data via ID (e.g. $locations[$id]['name']), which seems to be what you'd generally be wanting to do.
You can use array_map function which applies your custom action to each element in given array.
array_map(
function($arr) { if ($arr['id'] == $_GET['id']) echo $arr['name']; },
$locations
);
Doing this with PHP's built-in array functions* avoids a foreach loop:
<?php
$locations = [["id"=>202, "name"=>"GXP Club - Fable"], ["id"=>204, "name"=>"GXP Club - Gray"]];
$col = array_search(array_column($locations, "id"), $_GET["id"]);
echo $locations[$col]["name"];
Or, using a different method:
<?php
$locations = [["id"=>202, "name"=>"GXP Club - Fable"], ["id"=>204, "name"=>"GXP Club - Gray"]];
$result = array_filter($locations, function($v){ return $v["id"] == $_GET["id"]; });
echo array_shift($result)["name"];
* Notably, array_column() was not available until PHP 5.5, released 10 months after this question was asked!
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.
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 );