Storing value in unknown depth of multidimensional array - php

I have this exath path saved somewhere:
Array
(
[0] => library
[1] => 1
[2] => book
[3] => 0
[4] => title
[5] => 1
)
I have some array and I want to change the value on this index:
$values[library][1][book][0][title][1] = "new value";
I have no idea, how to do this, because there can be any (unknown) number of dimensions. Any hints?

It makes sense to create a function that does this, so:
function array_path_set(array & $array, array $path, $newValue) {
$aux =& $array;
foreach ($path as $key) {
if (isset($aux[$key])) {
$aux =& $aux[$key];
} else {
return false;
}
}
$aux = $newValue;
return true;
}
$values = array(
'library' => array(
1 => array(
'book' => array(
0 => array(
'title' => array(
1 => 'MAGIC VALUE!',
),
),
),
),
),
);
$path = array('library', 1, 'book', 0, 'title', 1);
$newValue = 'ANOTHER MAGIC VALUE!';
var_dump($values);
var_dump(array_path_set($values, $path, $newValue));
var_dump($values);

Try
foreach ($array as $val) {
$indexes .= "[$val]";
}
${'output'.$indexes} = 'something';
Or
$indexes = '';
foreach ($array as $val) {
$indexes .= "[$val]";
}
$output = 'values'.$indexes;
$$output = 'something';

Are you trying to provide a new value for the title of book 0 in library 1? If so, you will have to search for library "1", with book "0" and then change the value of the "title". So if all your values in the array have the same six entries, start with loc = 0 look at the values at loc+1 (library id), loc+3 (book id) and loc+5 .. change title) .. if not increment loc by 6 and continue searching.
[sounds like homework, so no code provided. Pardon me if I am wrong.]

Just in case you weren't aware of it, the key
$values["library"][1]["book"][0]["title"][1]
Is not the same as the array example in your post. Presuming the array is $values, it has five elements:
$values = Array
(
[0] => "library"
[1] => 1
[2] => "book"
[3] => 0
[4] => "title"
[5] => 1
)
$values[0] = "Library";
$values[1] = "1";
$values[2] = "book";
$values[3] = "0";
etc...
Is this array structure what you intended? If not, post back with a more complete structure so we can help.
Also, you need quotes around the strings - I have included for clarity
You could take a look at the following link for array_search. Some of the posters have included examples of a multidimensional array search and there are other examples. Do a google search on "multidimensional array search" and you will likely find a solution. If you need more direction, post back your details.

try this ->
$keys = array('0'=>'for','1'=>'test','2'=>'only');
$value='ok';
function addArrayPathWithValue($keys,$value,$array = array(),$current =
array())
{
$function = __FUNCTION__;
if (count($current)==0)
{
$keys = array_reverse($keys);
$current = $value;
}
if (count($keys)==0)
{
return $current;
}
$array[array_shift($keys)]=$current;
return $function($keys,$value,NULL,$array);
}
$array = addArrayPathWithValue($keys,$value);
print_r($array);
//output: Array ( [for] => Array ( [test] => Array ( [only] => ok ) ) )

Related

PHP combine several arrays to one

I want to combine several arrays into one, they are the result of a form post with an unknown number of elements, eg:
$ids = [53,54,55];
$names = ['fire','water','earth'];
$temps = [500,10,5];
What i want is to make a function that takes these arrays as an input and produces a single output, like
$elements = [['id'=>53,'name'=>'fire','temp'=>500] , ['id'=>54,'name'=>'water','temp'=>500] , ['id'=>55,'name'=>'earth','temp'=>500]]
I came up with the following solution:
function atg($array) {
$result = array();
for ($i=0;$i<count(reset($array));$i++) {
$newAr = array();
foreach($array as $index => $val) {
$newAr[$index] = $array[$index][$i];
}
$result[]=$newAr;
}
return $result;
}
It can be called like
$elements = atg(['id' => $ids, 'name' => $names, 'temp' => $temps]);
And it produces the right output. To me it seems a bit overly complicated though, and I'm sure this is a common problem in PHP for form posts, combining seperate fields into a single array per item. What would be a better solution?
You can loop through all of your 3 arrays at once with array_map(). There you can just return the new array with a value of each of the 3 arrays, e.g.
$result = array_map(function($id, $name, $temp){
return ["id" => $id, "name" => $name, "temp" => $temp];
}, $ids, $names, $temps);
Use below code:-
$ids = [53,54,55];
$names = ['fire','water','earth'];
$temps = [500,10,5];
$result = [];
foreach($ids as $k=>$id){
$result[$k]['id'] = $id;
$result[$k]['name'] =$names[$k];
$result[$k]['temp'] = $temps[0];
}
echo '<pre>'; print_r($result);
output:-
Array
(
[0] => Array
(
[id] => 53
[name] => fire
[temp] => 500
)
[1] => Array
(
[id] => 54
[name] => water
[temp] => 500
)
[2] => Array
(
[id] => 55
[name] => earth
[temp] => 500
)
)
If you are ok with a destructive solution, array_shift could do the trick :
$elements = array();
while (!empty($ids)) {
$elements[] = array(
'id' => array_shift($ids),
'name' => array_shift($names),
'temp' => array_shift($temps),
);
}
If you want to make a function, using the same arguments than your example, a solution could be
function atg($array) {
$elements = array();
while (!empty($array[0])) {
$new_element = array();
foreach ($array as $key_name => $array_to_shift) {
$new_element[$key_name] = array_shit($array_to_shift);
}
$elements[] = $new_element;
}
return $elements;
}
$result[$ids]['name'] = $names[0];
$result[$ids]['temp'] = $temps[0]

Replace IDs inside array with PHP

I have an array like this:
Array
(
[1] => Array
(
[uris] => Array
(
[1] => /
[2] => /news/
[3] => /about/
[4] => /contact/
)
[templates] => Array
(
[1] => 1
[2] => 2
[3] => 3
[4] => 4
)
)
)
and I need to update all the IDs with a new set of values so the final output should be something like:
[uris] => Array
(
[100] => /
[101] => /news/
[102] => /about/
[103] => /contact/
)
[templates] => Array
(
[100] => 1
[101] => 2
[102] => 3
[103] => 4
)
I think I might need to use a regex pattern like '/(\[.*?\])/' but I'm not sure how to put it together to get the final updated output.
EDIT: I should mention that the IDs I'm updating to won't be in sequential order, they're coming from a database table of entries in a CMS. Entries are being duplicated so they'll have the same URIs but the second set with have a higher set of IDs than the original ones.
There won't be a rule for the second set of IDs. The only guarantee is that the second set will all be higher than the highest ID from the first set.
The CMS I'm working with allows me to duplicate entries for use on a second site. But the CMS also uses a third party module that creates a serialized array like I've posted above which matches URIs against templates. The module doesn't create a new serialized array of the new entry IDs when the entries get duplicated, so what's I'm trying to do manually.
I thought I could unserialize the array, update the string's old IDs with the corresponding IDs of the new entries, reserialize it, and then copy it back into the database.
Array (
[1] => /
[2] => /news/
[3] => /about/
[4] => /contact/
)
Given this kind of array, what you need to do to replace the keys is simply:
$array = array_combine(range(100, 100 + (count($array) - 1)), $array);
It generates keys [100, .., 103] and splices them into the array.
You might have to loop and then replace the keys :
foreach ($yourArray as $array) {
for ($i = 0; $i < count($array['uris']); $i++) {
$array['uris'][$i][$newkey] = $array['uris'][$i][$oldkey];
unset($array['uris'][$i][$oldkey]);
}
for ($i = 0; $i < count($array['templates']); $i++) {
$array['templates'][$i][$newkey] = $array['templates'][$i][$oldkey];
unset($array['templates'][$i][$oldkey]);
}
}
As per your question update; not too sure what you're trying to do, but I have two guesses.
arr2d_replace_id will take all the uris and increase key and also a new set of array with updated keys and it's value.
arr2d_replace_id2 will 1) flip array of templates - where I'm guessing the value represents the ID of route in uris and so flipped to preserve values; 2) increase key value on uris; 3) change flipped array's value according to the key based on uris; 4) flip the array back with the new set info and assign to result.
function arr2d_replace_id($arr, $inc) {
$result = array();
foreach ($arr['uris'] as $k=>$v) {
$result['uris'][intval($k) + $inc] = $v;
$result['templates'][intval($k) + $inc] = $arr['templates'][$k];
}
return $result;
}
function arr2d_replace_id2($arr, $inc) {
$result = array();
$tpl_flipped = array_flip($arr['templates']);
foreach ($arr['uris'] as $k=>$v) {
$result['uris'][intval($k) + $inc] = $v;
$tpl_flipped[$k] = intval($k) + $inc;
}
$result['templates'] = array_flip($tpl_flipped);
return $result;
}
$test = array(
'uris' => array(
1 => '/', '/news/', '/about/', '/contact/',
),
'templates' => array(
1 => 1, 2, 3, 4
)
);
print_r( $test );
print_r( arr2d_replace_id($test, 100) );
print_r( arr2d_replace_id2($test, 100) );
See in action: http://3v4l.org/T6hHD
If the array values are unique, you can use array_flip:
$array = [
1 => '/',
2 => '/contact/',
3 => '/about/'
];
$counter = 100;
$array = array_flip($array);
$array = array_map(function($oldKey) use (&$counter) {
return ++$counter;
}, $array);
$array = array_flip($array);
$mainArray = array();
$mainArray[]=array("uris" => array("/", '/news', '/about', '/contact') , "templates" => array(1,2,3,4));
foreach ($mainArray as &$array) {
$uris = $array['uris'];
$keys = array_keys($uris);
for($i=0;$i<count($keys);$i++)
{
$uris[$keys[$i] + 100]=$uris[$i];
unset($uris[$i]);
}
$template = $array['templates'];
$keys = array_keys($uris);
for($i=0;$i<count($keys);$i++)
{
$template[$keys[$i] + 100]=$template[$i];
unset($template[$i]);
}
$array['uris'] = $uris;
$array['templates'] = $template;
}
echo "<pre>";
print_r($mainArray);
exit;
Try this one,
$array = array(
array('uris' => array(
'1' => '/',
'2' => '/news/',
'3' => '/about/',
'4' => '/contact/'
),
'templates' => array
(
'1' => '1',
'2' => '2',
'3' => '3',
'4' => '4'
)
)
);
$val = 100;
$result = array();
foreach ($array as $key => $value) {
foreach ($value as $key1 => $value1) {
foreach ($value1 as $key2 => $value2) {
$result[$key][$key1][$val] = $value2;
$val++;
}
}
}
var_dump($result);

How to group the result of array in two categories in PHP?

I have data here:
Array
(
[1] => Array
(
[SiteID] => 1
[OwnerAID] => 1
)
[3] => Array
(
[SiteID] => 3
[OwnerAID] => 1
)
[6] => Array
(
[SiteID] => 6
[OwnerAID] => 2
)
)
Now, I need to group the OwnerAID into two categories: the first one is OwnerAID owning only one SiteID and the second one is OwnerAID owning more than 1 SiteID.
I've tried to make a program and do some research, but the output of my code is wrong.
Please see my code:
public function groupIndividualAndAggregateSites()
{
$arrays = array();
foreach($this->combined as $key => $key_value)
{
$SiteID = "";
if ($SiteID == "") {
$SiteID=array($key_value['SiteID']); }
else {
$SiteID = array_merge((array)$SiteID, (array)$key_value['SiteID']);
$SiteID = array_unique($SiteID);
}
} if ($SiteID != "") {
$arrays = array('AID'=>$key_value['AID'], 'Sites' => $SiteID);
}
print_r($arrays);
}
The result should be shown like this:
Array(
[1] => Array
( [Sites] => Array ([0] => 1, [1] => 3)))
Array(
[2] => Array
( [Sites] => Array ([0] => [6]))
What you should go for is array:
$owners = array(
owner_1 => SiteID1, // int Only one site
owner_2 => array (SiteID2,SiteID3), // array Multiple sites
);
and later use the array $owners like:
echo (is_array($owners[$owner_1]) ? 'Has multiple sites' : 'has one site';
Thats the basic idea of small memory footprint.
Example, not tested.
public function groupIndividualAndAggregateSites() {
$owners = array();
foreach($this->combined as $key => $value) {
$owner_id = $value['OwnerAID'];
$site_id = $value['SiteID'];
if(array_key_exists($owner_id,$owners)) {
// He has one or more sites already?
if(is_array($owners[$owner_id]){
array_push($owners[$owner_id],$site_id);
} else {
// User already has one site. Lets make an array instead and add old and new siteID
$old_site_id = $owners[$owner_id];
$owners[$owner_id] = array($old_site_id,$owner_id);
}
} else {
$owners[$owner_id] = $site_id;
}
return $owners;
}
All you need to do is loop over your initial array, appending each OwnerAID to the relevant output subarray as determined by the SiteID:
$output = array(1=>array(), 2=>array());
foreach ($original as $v) $output[$v['SiteID'] == 1 ? 1 : 2][] = $v['OwnerAID'];
Here I am using the following features:
array() initialisation function;
foreach control structure;
ternary operator;
$array[$key] addressing;
$array[] pushing.

parsing out the last number of the post

Ok so i have a post that looks kind of this
[optional_premium_1] => Array
(
[0] => 61
)
[optional_premium_2] => Array
(
[0] => 55
)
[optional_premium_3] => Array
(
[0] => 55
)
[premium_1] => Array
(
[0] => 33
)
[premium_2] => Array
(
[0] => 36 )
[premium_3] => Array
(
[0] => 88 )
[premium_4] => Array
(
[0] => 51
)
how do i get the highest number out of the that. So for example, the optional "optional_premium_" highest is 3 and the "premium_" optional the highest is 4. How do i find the highest in this $_POST
You could use array_key_exists(), perhaps something like this:
function getHighest($variableNamePrefix, array $arrayToCheck) {
$continue = true;
$highest = 0;
while($continue) {
if (!array_key_exists($variableNamePrefix . "_" . ($highest + 1) , $arrayToCheck)) {
$continue = false;
} else {
highest++;
}
}
//If 0 is returned than nothing was set for $variableNamePrefix
return $highest;
}
$highestOptionalPremium = getHighest('optional_premium', $_POST);
$highestPremium = getHighest('premium', $_POST);
I have 1 question with 2 parts before I answer, and that is why are you using embedded arrays? Your post would be much simpler if you used a standard notation like:
$_POST['form_input_name'] = 'whatever';
unless you are specifically building this post with arrays for some reason. That way you could use the array key as the variable name and the array value normally.
So given:
$arr = array(
"optional_premium_1" => "61"
"optional_premium_2" => "55"
);
you could use
$key = array_keys($arr);
//gets the keys for that array
//then loop through get raw values
foreach($key as $val){
str_replace("optional_premium_", '', $val);
}
//then loop through again to compare each one
$highest = 0;
for each($key as $val){
if ((int)$val > $highest) $highest = (int)$val;
}
that should get you the highest one, but then you have to go back and compare them to do whatever your end plan for it was.
You could also break those into 2 separate arrays and assuming they are added in order just use end() http://php.net/manual/en/function.end.php
Loop through all POST array elements, pick out elements having key names matching "name_number" pattern and save the ones having the largest number portion of the key names. Here is a PHP script which does it:
<?php // test.php 20110428_0900
// Build temporary array to simulate $_POST
$TEMP_POST = array(
"optional_premium_1" => array(61),
"optional_premium_2" => array(55),
"optional_premium_3" => array(55),
"premium_1" => array(33),
"premium_2" => array(36),
"premium_3" => array(88),
"premium_4" => array(51),
);
$names = array(); // Array of POST variable names
// loop through all POST array elements
foreach ($TEMP_POST as $k => $v) {
// Process only elements with names matching "word_number" pattern.
if (preg_match('/^(\w+)_(\d+)$/', $k, $m)) {
$name = $m[1];
$number = (int)$m[2];
if (!isset($names[$name]))
{ // Add new POST var key name to names array
$names[$name] = array(
"name" => $name,
"max_num" => $number,
"key_name" => $k,
"value" => $v,
);
} elseif ($number > $names[$name]['max_num'])
{ // New largest number in key name.
$names[$name] = array(
"name" => $name,
"max_num" => $number,
"key_name" => $k,
"value" => $v,
);
}
}
}
print_r($names);
?>
Here is the output from the script:
Array
(
[optional_premium] => Array
(
[name] => optional_premium
[max_num] => 3
[key_name] => optional_premium_3
[value] => Array
(
[0] => 55
)
)
[premium] => Array
(
[name] => premium
[max_num] => 4
[key_name] => premium_4
[value] => Array
(
[0] => 51
)
)
)
Though ineffective, you could try something like
$largest = 0;
foreach($_POST as $key => $value)
{
$len = strlen("optional_premium_");
$num = substr($key, $len);
if($num > $largest)
$largest = $num;
}
print_r($largest);
The problem being that this will only work for one set of categories. It will most likely give errors throughout the script.
Ideally, you would want to reorganize your post, make each array be something like
[optional_premium_1] => Array
(
[0] => 61
["key"] => 1
)
[optional_premium_2] => Array
(
[0] => 61
["key"] => 2
)
Then just foreach and use $array["key"] to search.

weird php array

my php array looks like this:
Array (
[0] => dummy
[1] => stdClass Object (
[aid] => 1
[atitle] => Ameya R. Kadam )
[2] => stdClass Object (
[aid] => 2
[atitle] => Amritpal Singh )
[3] => stdClass Object (
[aid] => 3
[atitle] => Anwar Syed )
[4] => stdClass Object (
[aid] => 4
[atitle] => Aratrika )
) )
now i want to echo the values inside [atitle].
to be specific i want to implode values of atitle into another variable.
how can i make it happen?
With PHP 5.3:
$result = array_map(function($element) { return $element->atitle; }, $array);
if you don't have 5.3 you have to make the anonymous function a regular one and provide the name as string.
Above I missed the part about the empty element, using this approach this could be solved using array_filter:
$array = array_filter($array, function($element) { return is_object($element); });
$result = array_map(function($element) { return $element->atitle; }, $array);
If you are crazy you could write this in one line ...
Your array is declared a bit like this :
(Well, you're probably, in your real case, getting your data from a database or something like that -- but this should be ok, here, to test)
$arr = array(
'dummy',
(object)array('aid' => 1, 'atitle' => 'Ameya R. Kadam'),
(object)array('aid' => 2, 'atitle' => 'Amritpal Singh'),
(object)array('aid' => 3, 'atitle' => 'Anwar Syed'),
(object)array('aid' => 4, 'atitle' => 'Aratrika'),
);
Which means you can extract all the titles to an array, looping over your initial array (excluding the first element, and using the atitle property of each object) :
$titles = array();
$num = count($arr);
for ($i=1 ; $i<$num ; $i++) {
$titles[] = $arr[$i]->atitle;
}
var_dump($titles);
This will get you an array like this one :
array
0 => string 'Ameya R. Kadam' (length=14)
1 => string 'Amritpal Singh' (length=14)
2 => string 'Anwar Syed' (length=10)
3 => string 'Aratrika' (length=8)
And you can now implode all this to a string :
echo implode(', ', $titles);
And you'll get :
Ameya R. Kadam, Amritpal Singh, Anwar Syed, Aratrika
foreach($array as $item){
if(is_object($item) && isset($item->atitle)){
echo $item->atitle;
}
}
to get them into an Array you'd just need to do:
$resultArray = array();
foreach($array as $item){
if(is_object($item) && isset($item->atitle)){
$resultArray[] = $item->atitle;
}
}
Then resultArray is an array of all the atitles
Then you can output as you'd wish
$output = implode(', ', $resultArray);
What you have there is an object.
You can access [atitle] via
$array[1]->atitle;
If you want to check for the existence of title before output, you could use:
// generates the title string from all found titles
$str = '';
foreach ($array AS $k => $v) {
if (isset($v->title)) {
$str .= $v->title;
}
}
echo $str;
If you wanted these in an array it's just a quick switch of storage methods:
// generates the title string from all found titles
$arr = array();
foreach ($array AS $k => $v) {
if (isset($v->title)) {
$arr[] = $v->title;
}
}
echo implode(', ', $arr);
stdClass requires you to use the pointer notation -> for referencing whereas arrays require you to reference them by index, i.e. [4]. You can reference these like:
$array[0]
$array[1]->aid
$array[1]->atitle
$array[2]->aid
$array[2]->atitle
// etc, etc.
$yourArray = array(); //array from above
$atitleArray = array();
foreach($yourArray as $obj){
if(is_object($obj)){
$atitleArray[] = $obj->aTitle;
}
}
seeing as how not every element of your array is an object, you'll need to check for that.

Categories