Applying a variable level array to an existing array - php

I have two arrays, one of which is a "section" of the other. For example:
$array = array('file_name1'=>'date1',
'file_name2'=>'date2',
'file_name3'=> array('file_name3.1'=>'date3.1',
'file_name3.2'=>'date3.2'),
'file_name4'=>'date4');
$array_part = array('file_name3'=>array('file_name3.2'=>'date3.2.2'));
In my script, the first array holds a directory structure with the final values being the last-modified date. When I find a change, I want to apply the date value from the second array into the original array. Both arrays are dynamically created, so I don't know the depth of either array. How can I apply this value to the original array?

You are most likely looking for array_replace_recursive:
print_r(
array_replace_recursive($array, $array_part)
);
Which gives in your case:
Array
(
[file_name1] => date1
[file_name2] => date2
[file_name3] => Array
(
[file_name3.1] => date3.1
[file_name3.2] => date3.2.2
)
[file_name4] => date4
)
Example Code (Demo):
<?php
/**
* Applying a variable level array to an existing array
*
* #link http://stackoverflow.com/q/18519457/367456
*/
$array = array('file_name1' => 'date1',
'file_name2' => 'date2',
'file_name3' => array('file_name3.1' => 'date3.1',
'file_name3.2' => 'date3.2'),
'file_name4' => 'date4');
$array_part = array('file_name3' => array('file_name3.2' => 'date3.2.2'));
print_r(
array_replace_recursive($array, $array_part)
);

you can use php referneces
a data can be found here:
http://php.net/manual/en/language.references.pass.php
<?php
function foo(&$var)
{
$var++;
}
function &bar()
{
$a = 5;
return $a;
}
foo(bar());
?>

Related

Restructuring Multi Dimensional Array Format

I am struggling with what would appear to be a pretty straight forward task. I have looked at and tried all kinds of functions and suggestion on SO hoping that maybe there is something simple and functional out there. Nothing I tried gives me the logic to do the restructuring.
I have a long complex array. However very much simplified the logic problem I am trying to solve generically is as follows:
$cost_type = Array
(
0 => "ISP2",
1 => "ISP3",
2 => "ISP4"
);
$supplier_name = Array
(
0 => "NAME-A",
1 => "NAME-B",
2 => "NAME-C"
);
$propertyid = Array
(
0 => "property1",
1 => "property2",
2 => "property2"
);
and I need to convert it to the following set of arrays (noting the concatenation of the two arrays with a common property id.....
$property1
(
array['charges']
[0] =>IPS2
array ['names']
[0] =>NAME-A
)
$property2
(
array['charges']
[0] ->IPS3
[1] =>IPS4
array['names']
[0] =>NAME-B
[1] =>NAME-c
)
I have tried everything over the course of the last few hours and a simple solution totally evades me.
If you can join the three arrays as you say in comments above this code will generate the look you want.
I loop through the array with property and keep key as the key to find names and charges in the other subarrays.
$cost_type = Array
(
0 => "ISP2",
1 => "ISP3",
2 => "ISP4"
);
$supplier_name =Array
(
0 => "NAME-A",
1 => "NAME-B",
2 => "NAME-C"
);
$propertyid = Array
(
0 => "property1",
1 => "property2",
2 => "property2"
);
$arr[] = $cost_type;
$arr[] = $supplier_name;
$arr[] = $propertyid;
$result = array();
Foreach($arr[2] as $key => $prop){
$result[$prop]["charges"][] =$arr[0][$key];
$result[$prop]["names"][] = $arr[1][$key];
}
Var_dump($result);
https://3v4l.org/EilvE
The following code converts the original array in the expected result:
$res = array();
foreach($arr[2] as $k => $foo){ // foreach property
if(!isset($res[$foo])){ // add property if not yet in list
$res[$foo] = array(
'charges' => array($arr[0][$k]),
'names' => array($arr[1][$k])
);
}else{ // add new value to already existing property
$res[$foo]['charges'][] = $arr[0][$k];
$res[$foo]['names'][] = $arr[1][$k];
}
}
Check it out here: https://eval.in/904473
Of course, it assumes a bunch on things about the data, but it should work for any number of items.
And if you need the property in another variable, just access it with $res['name of it].
Run this code you will get smiler result as you want :
$twodimantion=array();
$properties=array('property1','property2','property3');
$charges=array('ISP2','ISP3','ISP4');
$names=array('NAME-A','NAME-B','NAME-C');
foreach ($properties as $key => $property) {
$twodimantion['charge'][$key]=$charges[$key];
$twodimantion['names'][$key]=$names[$key];
$twoarray[$property]=$twodimantion;
}
echo '<pre>';
print_r($twoarray);
echo '</pre>';
I can't say I completely follow what you are trying to do, but I think this may be part of the way there for you.
When trying to restructure data in PHP, it's often helpful to create a empty array (or other data structure) to store the new data in first. Then you find a way to loop over your initial data structure that allows you to insert items into your reformatted structure in the right sequence.
<?php
$properties = []; // Array to hold final result
// Loop over your initial inputs
foreach ($groupsOfValues as $groupName => $groupValues) {
$temp = []; // Array to hold each groupings reformatted data
// Loop over the items in one of the inputs
for ($i=0; $i<count($group) && $i<count($properties)+1; $i++) {
if (!is_array($temp[$groupName])) {
$temp[$groupName] = [];
}
$temp[$groupName][] = $group[$i];
}
$properties[] = $temp;
}

Move array element by associative key to the beginning of an array

So far all my research has shown that this cannot be achieved without writing lengthy functions such as the solution here
Surely there is a simpler way of achieving this using the predefined PHP functions?
Just to be clear, I am trying to do the following:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
// Call some cool function here and return the array where the
// the element with key 'bla2' has been shifted to the beginning like so
print_r($test);
// Prints bla2=1234, bla=>123 etc...
I have looked at using the following functions but have so far have not been able to write a solution myself.
array_unshift
array_merge
To Summarize
I would like to:
Move an element to the beginning of an array
... whilst maintaining the associative array keys
This seems, funny, to me. But here ya go:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
//store value of key we want to move
$tmp = $test['bla2'];
//now remove this from the original array
unset($test['bla2']);
//then create a new array with the requested index at the beginning
$new = array_merge(array('bla2' => $tmp), $test);
print_r($new);
Output looks like:
Array
(
[bla2] => 1234
[bla] => 123
[bla3] => 12345
)
You could turn this into a simple function that takes-in a key and an array, then outputs the newly sorted array.
UPDATE
I'm not sure why I didn't default to using uksort, but you can do this a bit cleaner:
$test = array(
'bla' => 123,
'bla2' => 1234,
'bla3' => 12345
);
//create a function to handle sorting by keys
function sortStuff($a, $b) {
if ($a === 'bla2') {
return -1;
}
return 1;
}
//sort by keys using user-defined function
uksort($test, 'sortStuff');
print_r($test);
This returns the same output as the code above.
This isn't strictly the answer to Ben's question (is that bad?) - but this is optimised for bringing a list of items to the top of the list.
/**
* Moves any values that exist in the crumb array to the top of values
* #param $values array of options with id as key
* #param $crumbs array of crumbs with id as key
* #return array
* #fixme - need to move to crumb Class
*/
public static function crumbsToTop($values, $crumbs) {
$top = array();
foreach ($crumbs AS $key => $crumb) {
if (isset($values[$key])) {
$top[$key] = $values[$key];
unset($values[$key]);
}
}
return $top + $values;
}

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

Retrieve value of child key in multidiensional array without knowing parent key

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

Extract elements from array so it only consists values of a specified index

I have an array
array(
array('total'=>10,'v'=>3229),
array('total'=>20,'v'=>3129),
array('total'=>30,'v'=>3391),
);
is there a one line way to convert the above to the following in PHP?
array(10,20,30);
You could use array_map, but it takes a little more than one line, unless you have PHP 5.3+:
$original = array(
array('total'=>10,'v'=>3229),
array('total'=>20,'v'=>3129),
array('total'=>30,'v'=>3391),
);
// Callback function
function valueOnly ($element) {
return $element['total'];
}
$result = array_map('valueOnly', $original);
With PHP 5.3+:
$index = 'total';
$lambda = function ($value) use ($index) { return $value[$index]; };
// Here is the one-liner that can be reused if you save the $lamda-function.
$result = array_map($lambda, $original);
Either way, I suggest you make a method of this since it increases readability and reusability.
There always is in a semicolon terminated sentences language:
foreach ($a as $v){ foreach($v as $k=>$v2) { if($k == 'total') {$r[] = $v2;}}};
Now I wouldn't write this.
This I might write, but you have to create a function first, which sums up to more than one line (or not, but I refuse to write this in a single line :-) )
function get_value($x) {
return $x['total'];
}
$r = array_map("get_value",$a);
Define one-line. As Vinko showed, there can be a great number of statements on one line. Here's the best one-line solution I can think of at the moment (the one-liner being the foreach statement):
$arr1 = array(
array('total'=>10,'v'=>3229),
array('total'=>20,'v'=>3129),
array('total'=>30,'v'=>3391),
);
$arr2 = array();
foreach ($arr1 as $item) $arr2[] = $item['total'];
Obviously there is more than one line, but I'm assuming you already have the $arr1 and $arr2 arrays initialized.
I have two really cool methods that work together for your purpose (and variations of it).
/**
* Pivots a 2 dimensional array.
*
* Turns the column names in a two dimensional array into the rows,
* using the original array's row indexes as column names. The input
* array and its rows may be integer-indexed or a hash.
*
* You can optionally specify a column or list of columns to return as rows
*
* Example -
* <pre>
*
* input:
* $aIn => array([0] => array([name] => 'John Doe', [phone] => '555-1000', 'happy'),
* [1] => array([name] => 'Fred Doodle', [phone] => '555-2000', 'sad', [title] => 'President'),...
*
* output:
* array([name] => array([0] => 'John Doe', [1] => 'Fred Doodle',...),
* [phone] => array([0] => '555-1000', [1] => '555-2000',...),
* [0] => array([0] => 'happy', [1] => 'sad',...),
* [title] => array([1] => 'President'))
*
* </pre>
* #param array $aInput A two dimensional array
* #param mixed $mColumns An array of columns or single column name. If nothing
* passed, then all columns from each input row will become rows
* in the output array.
* #return array Pivoted array !!! If a single column name is passed in $mColumns
* The return will be a one-dimensional array; you will get back
* an array of the values for that column.
*/
static function pivot($aIn, $mColumns = null) {
// Initialize the output
$aOut = array();
/*
* If input list of column names, then initialize, in case the
* input array is empty or doesn't have those columns
*/
if (is_array($mColumns) && !empty($mColumns)) {
foreach ($mColumns as $col) {
$aOut[$col] = array();
}
}
/*
* Output array needs to be passed inside an array to be passed by reference.
*/
// TODO As of PHP 5.2.3, could replace callback arg below with simply "xarray::pivot_row", but production uses 5.1.6
array_walk($aIn, array("xarray", "pivot_row"), array(&$aOut));
return (empty($aOut) || is_null($mColumns) ? $aOut : (is_array($mColumns) ? array_intersect_key($aOut, array_flip($mColumns)) : $aOut[$mColumns]));
}
public static function pivot_row($aRow, $mKey, $aSpec) {
foreach ($aRow as $k => $v) {
$aSpec[0][$k][$mKey] = $v;
}
}
Nasty solution:
$source = array(
array('total'=>10,'v'=>3229),
array('total'=>20,'v'=>3129),
array('total'=>30,'v'=>3391),
);
$totals = array_map( create_function('$a', 'return $a[\'total\'];'), $source );

Categories