I have 2 associative arrays: $arr1 & $arr2. I'd like to create $arr3, which would combine 'name' and 'character' if the dates match...if the dates don't match, then just the character:
Here's $arr1:
Array
(
[0] => stdClass Object
(
[date] => 2010/01/01
[name] => Mario Lopez
)
[1] => stdClass Object
(
[date] => 2010/01/02
[name] => Lark Voorhies
)
)
Here's $arr2:
Array
(
[0] => Array
(
[date] => 2010/01/01
[character] => AC Slater
)
[1] => Array
(
[date] => 2010/01/02
[character] => Lisa Turtle
)
[2] => Array
(
[date] => 2010/01/03
[character] => Kelly Kapowski
)
)
Using array_intersect gives the following error: "Object of class stdClass could not be converted to string".
Here's what I'd like to get, if it's possible (ie $arr3):
Array
(
[0] => stdClass Object
(
[date] => 2010/01/01
[name] => Mario Lopez
[character] => AC Slater
)
[1] => stdClass Object
(
[date] => 2010/01/02
[name] => Lark Voorhies
[character] => Lisa Turtle
)
[2] => stdClass Object
(
[date] => 2010/01/03
[character] => Kelly Kapowski
)
)
This function was posted on php.net and I've been using it for quite a while. It should do what you are asking for
function array_extend($a, $b) {
foreach($b as $k=>$v) {
if( is_array($v) ) {
if( !isset($a[$k]) OR isset($v[0])) {
$a[$k] = $v;
} else {
$a[$k] = array_extend($a[$k], $v);
}
} else {
$a[$k] = $v;
}
}
return $a;
}
Usage:
$array = array_extend($orig_array,$new_array);
Note that you will either have to convert your objects to arrays or modify the function to convert the object to an array on the fly ($a = (array) $a);
Edit:
Original source http://www.php.net/manual/en/function.array-merge.php#95294
Note that I made a small modification to resolve an issue with the given function where it would not properly extend an array with numeric keys
Related
I'm trying to group the arrays of a query, using the PHP foreach loop, to a group of objects without sub objects. But I'm not getting it, I've tried it in several ways. I'm using the following loop with foreach:
public function array_to_object($array)
{
$obj = new stdClass;
foreach($array as $k => $v) {
if(is_array($v)){
$obj->{$k} = $this->array_to_object($v); //RECURSION
} else {
$obj->{$k} = $v;
}
}
return $obj;
}
$users = $this->array_to_object($users);
print_r((array)$users);
I have this result:
Array
(
[0] => stdClass Object
(
[_id] => 12
[username] => lucaspedro
[first_name] => Lucas
[user_role] => stdClass Object
(
[ur_name] => Admin
)
)
[1] => stdClass Object
(
[_id] => 32
[username] => joaosilva
[first_name] => Joao
[user_role] => stdClass Object
(
[ur_name] => Member
)
)
)
But I need this result:
Array
(
[0] => stdClass Object
(
[_id] => 12
[username] => lucaspedro
[first_name] => Lucas
[ur_name] => Admin
)
[1] => stdClass Object
(
[_id] => 32
[username] => joaosilva
[first_name] => Joao
[ur_name] => Member
)
)
A simple foreach can do the trick for you.
foreach($array as $k=>$v){
$array[$k]->ur_name = $v->user_role->ur_name;
unset($array[$k]->user_role);
}
print_r($array);
I have two arrays and looking for the way to merge them. Standard array_merge() function don't work.
Do you know any nice solution without foreach iteration?
My first array:
Array
(
[0] => stdClass Object
(
[field_value] => Green
[count] =>
)
[1] => stdClass Object
(
[field_value] => Yellow
[count] =>
)
)
My second array:
Array
(
[0] => 2
[1] => 7
)
And as a result I would like to get:*
Array
(
[0] => stdClass Object
(
[field_value] => Green
[count] => 2
)
[1] => stdClass Object
(
[field_value] => Yellow
[count] => 7
)
)
This should work for you:
Just simply loop through both arrays with array_map() and pass the argument from array one as reference. Then you can simply assign the value to the count property.
<?php
array_map(function(&$v1, $v2){
$v1->count = $v2;
}, $arr1, $arr2);
print_r($arr1);
?>
output:
Array
(
[0] => stdClass Object
(
[field_value] => Green
[count] => 2
)
[1] => stdClass Object
(
[field_value] => Yellow
[count] => 7
)
)
[akshay#localhost tmp]$ cat test.php
<?php
$first_array = array(
(object)array("field_value"=>"green","count"=>null),
(object)array("field_value"=>"yellow","count"=>null)
);
$second_array = array(2,7);
function simple_merge($arr1, $arr2)
{
return array_map(function($a,$b){ $a->count = $b; return $a; },$arr1,$arr2);
}
print_r($first_array);
print_r($second_array);
print_r(simple_merge($first_array,$second_array));
?>
Output
[akshay#localhost tmp]$ php test.php
Array
(
[0] => stdClass Object
(
[field_value] => green
[count] =>
)
[1] => stdClass Object
(
[field_value] => yellow
[count] =>
)
)
Array
(
[0] => 2
[1] => 7
)
Array
(
[0] => stdClass Object
(
[field_value] => green
[count] => 2
)
[1] => stdClass Object
(
[field_value] => yellow
[count] => 7
)
)
it is simple
code:
$i = 0;
foreach($firstarrays as $firstarr)
{
$firstarr['count'] = $secondarray[$i];
$i++;
}
Another option:
$a1 = Array(
(object) Array('field_value' => 'Green', 'count' => null),
(object) Array('field_value' => 'Yellow', 'count' => null)
);
$a2 = Array(2, 7);
for ($i=0; $i<sizeof($a1); $i++) {
$a1[$i]->count=$a2[$i];
}
I want to merge the 2 arrays of objects based on the 'id' field of Array1 and the 'itemVendorCode' of Array2. I also wanted to remove from the resulting arrays of object anything that didn't match.
Array1:
Array
(
[0] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
)
[1] => stdClass Object
(
[id] => 89-575-2354
[qty] => 24
[price] => 230.35
)
[2] => stdClass Object
(
[id] => 89-605-1250
[qty] => 2
[price] => 230.35
)
)
Array2:
Array
(
[0] => Item Object
(
[internalId] => 14062
[itemVendorCode] => 89-605-1250
)
[1] => Item Object
(
[internalId] => 33806
[itemVendorCode] => 89-575-2354
)
[2] => Item Object
(
[internalId] => 64126
[itemVendorCode] => 26-295-1006
)
)
I was able to solve this by this code:
$indexed = array();
foreach($itemsArray as $value) {
$indexed[$value->itemVendorCode] = $value;
}
$results = array();
foreach($vendorItems as $obj) {
$value = $indexed[$obj->id];
if (isset($value)) {
foreach($value as $name => $val) {
$obj->$name = $val;
array_push($results, $obj);
}
}
}
print_r($results);
credits to the original poster. I just modified it a bit,
I was able to get the result like this:
Array
(
[0] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
[internalId] => 2035
[itemVendorCode] => 10-423-1176
)
[1] => stdClass Object
(
[id] => 10-423-1176
[qty] => 2
[price] => 12.6
[internalId] => 2035
[itemVendorCode] => 10-423-1176
)
[2] => stdClass Object
(
[id] => 14-102-1010
[qty] => 16
[price] => 3.2
[internalId] => 57033
[itemVendorCode] => 14-102-1010
)
)
I think you will have to use array_map function which provides you a callback function to execute on array(s).
In the callback function:
- declare your array1
- foreach the second array
- set an if statement to check that the current iteration with the id value matches the itemVendorCode of the array2 and return it
something like this:
// You have to specify to PHP to use a local copy of your $array2 to works with it into your callback
$cb = function ($obj1) use ($array2)
{
// you foreach this array
foreach ($array2 as $obj2) {
// if the value of id matches itemVendorCode
if ($obj1->id === $obj2->itemVendorCode) {
// you return the id
return $obj->id;
}
}
};
// this function will fill a new array with all returned data
$mergedArray = array_map($cb, $array1);
This code is a sample but doesn't provide you, your needled solution, try to update it to do what you exactly want ;)
I've spent the day playing with deceze's answer but I'm no closer to making it work. I may have part of it, but not sure how to get recursion in array_filter.
My Array looks like this (sample):
Array
(
[name] => root
[ChildCats] => Array
(
[0] => Array
(
[name] => Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Ducted Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Supply & Install
[ChildCats] => Array
(
[0] => Array
(
[name] => Daiken
[S] => 6067
)
)
)
[1] => Array
(
[name] => Supply Only
[ChildCats] => Array
(
[0] => Array
(
[name] => Mitsubishi
[S] => 6026
)
)
)
)
)
[1] => Array
(
[name] => Split System Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Supply & Install
[ChildCats] => Array
(
[0] => Array
(
[name] => Daiken
[S] => 6067
)
[1] => Array
(
[name] => Fujitsu Split Air Conditioning Systems
[S] => 6464
)
[2] => Array
(
[name] => Mitsubishi Electric Split Air Conditioning Systems
[S] => 6464
)
)
)
)
)
)
)
[1] => Array
(
[name] => Appliance / White Goods
[ChildCats] => Array
(
[0] => Array
(
[name] => Clearance
[S] => 6239
)
[1] => Array
(
[name] => Cooktops
[ChildCats] => Array
(
[0] => Array
(
[name] => Ceramic Cooktops
[S] => 6239
)
[1] => Array
(
[name] => Element Cooktops
[S] => 6067
)
[2] => Array
(
[name] => Gas Cooktops
[S] => 6239
)
[3] => Array
(
[name] => Induction Cooktops
[S] => 6239
)
)
)
)
)
Now lets say I try to extract just the parts of the array relevent to the following keypair:
S => 6067.
I'd like the result to look like:
Array
(
[name] => root
[ChildCats] => Array
(
[0] => Array
(
[name] => Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Ducted Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Supply & Install
[ChildCats] => Array
(
[0] => Array
(
[name] => Daiken
[S] => 6067
)
)
)
)
)
[1] => Array
(
[name] => Split System Air Conditioning
[ChildCats] => Array
(
[0] => Array
(
[name] => Supply & Install
[ChildCats] => Array
(
[0] => Array
(
[name] => Daiken
[S] => 6067
)
)
)
)
)
)
)
[1] => Array
(
[name] => Appliance / White Goods
[ChildCats] => Array
(
[0] => Array
(
[name] => Cooktops
[ChildCats] => Array
(
[0] => Array
(
[name] => Element Cooktops
[S] => 6067
)
)
)
)
)
)
)
What I cannot get my head arround is should I be creating a new array or using array filter.
Playing with deceze code I've got the search working using the following:
function recursive_assoc_in_array(array $haystack, array $needle, $childKey = 'ChildCats') {
if (array_intersect_assoc($haystack, $needle)) {
echo "Found via array_intersect_assoc ".$haystack[name]."\n";
return true;
}
foreach ($haystack[$childKey] as $child) {
if (recursive_assoc_in_array($child, $needle, $childKey)) return true;
}
return false;
}
But if I try to process with,
$array = array_filter($array, function (array $values) {
return recursive_assoc_in_array($values, array('S' => '6067'));
});
I get the original array which leads me to think I have to get recursion running on the array_filter query.
At this point I just go blank.
Additionally, the array keys will need to be reindexed on the produced new array. Any ideas?
--Additional 7/7/14
How about if I try to build a new array from the old one?
I'm trying:
function exploreArrayandAdd($Array) {
if ($Array['ChildCats']) {
foreach ($Array['ChildCats'] as $key => $value) {
$NewArray['ChildCats'][] = exploreArrayandAdd($value);
}
} else {
if ($Array['S'] == 6026) {
//echo "1";
return $Array;
}
}
}
But cannot work out how to pass the new array out of the function?
Tried removing branches that don't match using:
function exploreArray(&$Array) {
if ($Array['ChildCats']) {
foreach ($Array['ChildCats'] as $key => $value) {
$result = exploreArray($Array['ChildCats'][$key]);
if ($result === false)
unset($Array['ChildCats'][$key]);
}
} else {
// print_r($Array);
if ($Array['S'] == 6026) {
return true;
} else {
unset($Array);
return false;
}
}
//if ($NoChildCat==true) print_r($Array);
}
But I believe it is the wrong way as it does work at the bottom of the array but not back up towards the top as siblings make result true.
Also this won't reindex the array keys.
function recursive_array_filter(array $array, $childKey, callable $test) {
if (isset($array[$childKey]) && is_array($array[$childKey])) {
foreach ($array[$childKey] as $key => &$child) {
if (!$child = recursive_array_filter($child, $childKey, $test)) {
unset($array[$childKey][$key]);
}
}
if (!$array[$childKey]) {
unset($array[$childKey]);
}
}
return !empty($array[$childKey]) || $test($array) ? $array : [];
}
$array = recursive_array_filter($array, 'ChildCats', function (array $array) {
return array_intersect_assoc($array, ['S' => 6026]);
});
To express the algorithm in words: you descend down into the array first, following all ChildCats branches to their end. In each level you return the values as they are back to the caller if they match your test or if they have children, or you return an emptied array (you could also return false if you prefer). If some child turns out empty, you prune it with unset.
I have implemented the test as a callback function here for best reusability of the code.
I have a rather annoying array structure to work with and I need to sort it by any arbitrary key combination. 2 records are displayed below but multiple records with or without the same structure will be present when sorting is actioned.
Here are two records.
Array(
[0] => Array
(
[cid] => 1
[title] => Mr
[first_name] => Abet
[last_name] => Simbad
[emails] => Array
(
[374] => Array
(
[eid] => 374
[name] => ski lodge
[email] => simbad#skifree.com
)
[373] => Array
(
[eid] => 373
[name] => work
[email] => simbad#work.com
)
[375] => Array
(
[eid] => 375
[name] => personal
[email] => simbad#gmail.com
)
)
)
[1] => Array
(
[cid] => 2
[title] => Mrs
[first_name] => Angie
[last_name] => Stokes
[emails] => Array
(
[590] => Array
(
[eid] => 590
[name] => work
[email] => angie#gmail.com
)
)
)
So if I wanted to sort by email in ascending order in the emails array, how can I get the second complete record to come first in the result array? angie#gmail.com comes before simbad#....
Also Some records will not contain an emails array. They would be last in the result set.
Any help would be much appreciated.
The array shown is a cut down version but I have addresses, notes, phones and websites in the same annoying structure. Ideally I could sort with something like
$sort = array('emails','email')
$data = sort_data_func('ASC',$sort,$data);
But anything steps in the right direction will help. :)
Here's some code I have so far
$sort = array('emails','email');
foreach($contacts as $ckey => $c){
if(is_array($c[$sort[0]])){
foreach($c[$sort[0]] as $key1 => $sort0){
if($sort0[$sort[1]]!=''){
$res[$sort[0]][$ckey][$sort[1]][] = $sort0[$sort[1]];
}
}
}
}
print_r($res);
Which produces:
Array
(
[emails] => Array
(
[0] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
[1] => Array
(
[0] => angie#gmail.com
)
)
)
But I have no idea where to go from here.
EDIT
OK I have the records in the currect order now but how can I keep the initial record ID in the resulting array?
Here's what I'm using.
$direction=='ASC'
function cmp_asc($a, $b){
$key = current(array_keys($a));
sort($a[$key]);
$a[$key] = current($a[$key]);
sort($b[$key]);
$b[$key] = current($b[$key]);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
function cmp_desc($a, $b){
$key = current(array_keys($a));
asort($a[$key]);
$a[$key] = current($a[$key]);
asort($b[$key]);
$b[$key] = current($b[$key]);
if ($a == $b) {
return 0;
}
return ($a < $b) ? -1 : 1;
}
if($direction=='ASC'){
usort($res[$sort[0]], 'cmp_asc');
}else{
usort($res[$sort[0]], 'cmp_desc');
}
In
Array
(
[emails] => Array
(
[0] => Array
(
[email] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
)
[1] => Array
(
[email] => Array
(
[0] => angie#gmail.com
)
)
)
)
Out
Array
(
[emails] => Array
(
[0] => Array
(
[email] => Array
(
[0] => angie#gmnail.com
)
)
[1] => Array
(
[email] => Array
(
[0] => simbad#skifree.com
[1] => simbad#work.com
[2] => simbad#gmail.com
)
)
)
)
One of the usort functions, combined with a self-written comparison function that detects the order in which two elements should be sorted, should do the trick.