php setting value in multi dimensinal array depending on array of indices - php

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',
),
),
)

Related

How to get values of array 1 and array 2 based on array index of array3 in laravel/php? [duplicate]

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 );

PHP/Wordpress: Help me understand why the author of the tutorial uses array_keys() followed by array_flip()

I'm following this tutorial but have been struggling to understand a step in the insert_row() method. Here is the method in full:
// Adds new row to table
public function insert_row($data, $type='') {
global $wpdb;
// set defaults
$data = wp_parse_args( $data, $this->get_column_defaults());
do_action('add_pre_insert_' . $type, $data);
// initialise column format array
$column_formats = $this->get_columns();
// force fields to lower case
$data = array_change_key_case($data);
// remove unknown columns
$data = array_intersect_key($data, $column_formats);
// reorder $column_formats to match the order of columns in $data
$data_keys = array_keys($data);
$column_formats = array_merge(array_flip($data_keys), $column_formats);
$wpdb->insert($this->table_name, $data, $column_formats);
do_action('add_post_insert_'.$type, $wpdb->insert_id, $data);
return $wpdb->insert_id;
}
I cannot understand why the author assigns array_keys($data) to $data_keys then calls array_flip($data_keys) on the next line. What is happening there?
As I understand it, the keys of $data and array_flip($data_keys) are exactly the same. Though the values of array_flip($data_keys) would be 0,1,2,3,4,... But why? Wouldn't $column_formats overwrite those values anyway?
Ok,
So array_keys gets the keys of an array, so if you have this array
['one'=>'foo', 'two'=>'bar']
You get this from array keys:
[ 0 => 'one', 1=>'two']
Now if you flip that you get
['one' => 0, 'two' => 1]
AS to why, I have no idea. I would have to look deeper into the code and I would need some actual data that is used here.
You can test it with this bit of code (FYI I did this first bit in my head):
$a=['one'=>'foo', 'two'=>'bar'];
var_export($a);
$a = array_keys($a);
var_export($a);
$a = array_flip($a);
var_export($a);
Outputs:
array (
'one' => 'foo',
'two' => 'bar',
)array (
0 => 'one',
1 => 'two',
)array (
'one' => 0,
'two' => 1,
)
You can test it here
Once you add array_merge in any keys that exist will be replaced. Now if it was me just from a conceptual point, assuming you don't want those number in there if a key is missing, I would have used array_fill_keys instead of array_flip
$a=['one'=>'foo', 'two'=>'bar'];
var_export($a);
$a = array_keys($a);
var_export($a);
$a = array_fill_keys($a, '');
var_export($a);
Outputs
array (
'one' => 'foo',
'two' => 'bar',
)array (
0 => 'one',
1 => 'two',
)array (
'one' => '',
'two' => '',
)
As you can see the last array has just an empty string for the value, the previous way if an item is missing you get the number as the left over value. This way you would get an empty string as the left over value.
See it here
But like I said there is no way to know what their intent was without knowing what the data is that this works on. I am just "assuming" here (to make my point)

PHP getting values of the objects by key inside array

Hi all I have an array "$decodedData" of object from json data.
var_export($decodedData);
returns next:
array ( 0 => array ( 'number' => '2', 'type' => 'accs', ), 1 => array ( 'number' => '5', 'type' => 'accs', ), )
I'm trying to output all the "numbers" values:
foreach ($decodedData as $number)
{
echo implode(',', $number);
}
but I'm getting "type" values either
2,accs5,accs
How can I get rid of those?
You can use array_map to accomplish that.
The first parameter is a callback function that will receive each element and return something to replace it with. In this case, we are returning the number key of each element.
$result = array_map(function($val) {
return $val['number'];
}, $array);
echo implode(',', $result);
You're looping through an array of arrays, so $number is returning a complete array, not the number value. To access the number value of each, do something like this:
foreach ($decodedData as $number=>$val){
echo implode(',', $val['number']);
}

Understanding the basics of multidimensional arrays

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'];.

Get a subset of an array based on an array of keys

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 );

Categories