I have different multidimensional arrays with different keys and values:
$array_1 = array('cars' => array('audi' => array('a3' => array('one', 'two', 'three'), 'a5' => array('five', 'six', 'seven')), 'mercedes' => array('type_1' => array('submodel' => array('whatever'))), 'other_cat' => array('different_things')));
then I would like to unset a specific key, for example:
unset($array_1['cars']['audi']['a5']);
Now I like to "split it up", to have the key variable.
$to_unset = ['cars']['audi']['a5'];
How can I unset that specific (variable!) key?
AƤron
An easy utility to avoid removing array keys that do not exist by accident:
function removeArrayKey($path, &$array ) {
$array_temp = &$array;
$previousItem = null;
$path_bits = explode( ".", $path );
foreach( $path_bits as &$path_bit ) {
if( !isset( $array_temp[ $path_bit ] ) ) {
die("Error" . $path_bit);
//throw new Exception( "Path does not exist in array" );
}
$previousItem = &$array_temp;
$array_temp = &$array_temp[ $path_bit ];
}
if( isset( $previousItem ) ) {
unset( $previousItem[ $path_bit ] );
}
return $array;
}
To use the function, simply use removeArrayKey( "cars.mercedes.cars", $array_1 ); and separate each array index with a .
So as i see your problem, you'd like to save your array path into a variable. You can solve this problem on two different ways:
Save every key into a variable
The way i would do it, if my array structure looks always the same (e.g. [cars][type][model]). You can save the key to delete into a variable:
$cars = 'cars';
$type = 'audi';
$model = 'a5';
unset($array_1[$cars][$type][$model]);
This will work excellent in a for(each) loop.
Saving your keys into an array
This method will save your problem, but it is not the best option. You can save all the keys you like to unset into an array. This way can cause many bugs and you should reconsider your array structure, if this way is your solution.
// arrays start at 0
$to_unset = [
0 => 'cars',
1 => 'audi',
2 => 'a5',
];
unset($array_1[$to_unset[0]][$to_unset[1]][$to_unset[2]]);
An other possible option here is to name the keys of the $to_unset array.
// arrays start at 0
$to_unset = [
'cars' => 'cars',
'type' => 'audi',
'model' => 'a5',
];
unset($array_1[$to_unset['cars']][$to_unset['type']][$to_unset['model']]);
You can probably go with eval but it's not recommended.
eval('unset($array_1' . $to_unset . ');');
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',
),
),
)
So I have a result from a form post that looks like this:
$data = [
'id_1' => [
'0' => 1,
'1' => 2
],
'id_2' => [
'0' => 3,
'1' => 4
],
'id_3' => [
'0' => 5,
'1' => 6
]
];
What I want to achieve is to split this array into two different arrays like this:
$item_1 = [
'id_1' => 1,
'id_2' => 3,
'id_3' => 5
]
$item_2 = [
'id_1' => 2,
'id_2' => 4,
'id_3' => 6
]
I've tried using all of the proper array methods such as array_chunk, array_merge with loops but I can't seem to get my mind wrapped around how to achieve this. I've seen a lot of similar posts where the first keys doesn't have names like my array does (id_1, id_2, id_3). But in my case the names of the keys are crucial since they need to be set as the names of the keys in the individual arrays.
Much shorter than this will be hard to find:
$item1 = array_map('reset', $data);
$item2 = array_map('end', $data);
Explanation
array_map expects a callback function as its first argument. In the first line this is reset, so reset will be called on every element of $data, effectively taking the first element values of the sub arrays. array_map combines these results in a new array, keeping the original keys.
The second line does the same, but with the function end, which effectively grabs the last element's values of the sub-arrays.
The fact that both reset and end move the internal array pointer, is of no concern. The only thing that matters here is that they also return the value of the element where they put that pointer to.
Solution without loop and just for fun:
$result = [[], []];
$keys = array_keys($data);
array_map(function($item) use(&$result, &$keys) {
$key = array_shift($keys);
$result[0][$key] = $item[0];
$result[1][$key] = $item[1];
}, $data);
Just a normal foreach loop will do.
$item_1 = [];
$item_2 = [];
foreach ($data as $k => $v){
$item_1[$k] = $v[0];
$item_2[$k] = $v[1];
}
Hope this helps.
I am new to using multidimensional arrays with php, I have tried to stay away from them because they confused me, but now the time has come that I put them to good use. I have been trying to understand how they work and I am just not getting it.
What I am trying to do is populate results based on a string compare function, once I find some match to an 'item name', I would like the first slot to contain the 'item name', then I would like to increment the priority slot by 1.
So when when I'm all done populating my array, it is going to have a variety of different company names, each with their respective priority...
I am having trouble understanding how to declare and manipulate the following array:
$matches = array(
'name'=>array('somename'),
'priority'=>array($priority_level++)
);
So, in what you have, your variable $matches will point to a keyed array, the 'name' element of that array will be an indexed array with 1 entry 'somename', there will be a 'priority' entry with a value which is an indexed array with one entry = $priority_level.
I think, instead what you probably want is something like:
$matches[] = array(name => 'somename', $priority => $priority_level++);
That way, $matches is an indexed array, where each index holds a keyed array, so you could address them as:
$matches[0]['name'] and $matches[0]['priority'], which is more logical for most people.
Multi-dimensional arrays are easy. All they are is an array, where the elements are other arrays.
So, you could have 2 separate arrays:
$name = array('somename');
$priority = array(1);
Or you can have an array that has these 2 arrays as elements:
$matches = array(
'name' => array('somename'),
'priority' => array(1)
);
So, using $matches['name'] would be the same as using $name, they are both arrays, just stored differently.
echo $name[0]; //'somename';
echo $matches['name'][0]; //'somename';
So, to add another name to the $matches array, you can do this:
$matches['name'][] = 'Another Name';
$matches['priority'][] = 2;
print_r($matches); would output:
Array
(
[name] => Array
(
[0] => somename
[1] => Another Name
)
[priority] => Array
(
[0] => 1
[1] => 2
)
)
In this case, could this be also a solution with a single dimensional array?
$matches = array(
'company_1' => 0,
'company_2' => 0,
);
if (isset($matches['company_1'])) {
++$matches['company_1'];
} else {
$matches['company_1'] = 1;
}
It looks up whether the name is already in the list. If not, it sets an array_key for this value. If it finds an already existing value, it just raises the "priority".
In my opinion, an easier structure to work with would be something more like this one:
$matches = array(
array( 'name' => 'somename', 'priority' => $priority_level_for_this_match ),
array( 'name' => 'someothername', 'priority' => $priority_level_for_that_match )
)
To fill this array, start by making an empty one:
$matches = array();
Then, find all of your matches.
$match = array( 'name' => 'somename', 'priority' => $some_priority );
To add that array to your matches, just slap it on the end:
$matches[] = $match;
Once it's filled, you can easily iterate over it:
foreach($matches as $k => $v) {
// The value in this case is also an array, and can be indexed as such
echo( $v['name'] . ': ' . $v['priority'] . '<br>' );
}
You can also sort the matched arrays according to the priority:
function cmp($a, $b) {
if($a['priority'] == $b['priority'])
return 0;
return ($a['priority'] < $b['priority']) ? -1 : 1;
}
usort($matches, 'cmp');
(Sourced from this answer)
$matches['name'][0] --> 'somename'
$matches['priority'][0] ---> the incremented $priority_level value
Like David said in the comments on the question, it sounds like you're not using the right tool for the job. Try:
$priorities = array();
foreach($companies as $company) {
if (!isset($priorities[$company])) { $priorities[$company] = 0; }
$priorities[$company]++;
}
Then you can access the priorities by checking $priorities['SomeCompanyName'];.
Given this multidimensional array, I'm trying to retrieve the value of one of the child keys:
$movieCast = Array(
'1280741692' => Array(
...
, 'userid' => 62
, 'country_id' => '00002'
...
)
, '1280744592' => Array(
...
, 'userid' => 62
, 'country_id' => '00002'
...
)
)
How can I retrieve the value of country_id?
The top-level array key could be anything and the value of country_id will always be the same for a specific user. In this example, user #62's country_id will always be 00002.
You have to iterate through the outer array:
foreach ($outer as $inner) {
//do something with $inner["country_id"]
}
Another option is to build an array with the contry_ids (example uses PHP >=5.3 functionality, but that can be worked around easily in earlier versions):
array_map(function ($inner) { return $inner["country_id"]; }, $outer);
EDIT If the ids are all the same, even easier. Do:
$inner = reset($outer); //gives first element (and resets array pointer)
$id = $inner["country_id"];
a more general-purpose solution using php 5.3:
function pick($array,$column) {
return array_map(
function($record) use($column) {
return $record[$column];
},
$array
);
}
You need to use this:
array_column($movieCast, 'country_id')
The result will be:
array (
0 => '00002',
1 => '00002',
)