Related
I have 2 multi-dimensional arrays:
$category = array (
37 = array (id=1, name=joe, boss=kev)
73 = array (id=55, name=diane, boss=rox)
11 = array (id=4, name=bideo, boss=julia)
)
$other_variable = array (
1 = array (
picture1 = array (name=zee, id=4),
picture2 = array (name=izzy, id=1)
)
2 = array (
picture1 = array (name=foo, id=55),
picture2 = array (name=ido, id=44)
)
3 = array (
picture1 = array (name=wheez, id=87),
picture2 = array (name=ardu, id=9)
)
)
I want to combine them so that
$category = array (
37 = array (
id=1,
name=joe,
boss=kev,
other_variable = array (
picture1 = array (name=zee, id=4),
picture2 = array (name=izzy, id=1)
),
73 = array (
id=55,
name=diane,
boss=rox,
other_variable = array (
picture1 = array (name=foo, id=55),
picture2 = array (name=ido, id=44)
),
11 = array (
id=4,
name=bideo,
boss=julia,
other_variable = array (
picture1 = array (name=wheez, id=87),
picture2 = array (name=ardu, id=9)
)
)
I have tried
$new_array = array_map(null, $category, $other_variable);
That combines the two arrays, but it creates several nested levels in the array. I am looking for something much cleaner that maintains $category as the parent array.
Are you expecting something like this? Here we are using next and current function for incrementing internal pointer of array and getting current value.
Try this code snippet here
foreach($category as &$value)
{
$value["other_variable"]=current($other_variable);
next($other_variable);
}
print_r($category);
You were kind of on the right path with your use of array_map() to synchronously iterate two arrays, but sadly that function is going to kill your first level keys.
From the array_map() manual:
The returned array will preserve the keys of the array argument if and only if exactly one array is passed. If more than one array is passed, the returned array will have sequential integer keys.
array_walk() is going to be a cleaner / more appropriate function call for your task of modifying the $category array. array_walk() allows you to modify your $category array and synchronously iterate your $other_variable array (as the optional userdata parameter) without any additional iterated function calls (e.g. next()).
Code: (Demo)
$category=[
37=>["id"=>1,"name"=>"joe","boss"=>"kev"],
73=>["id"=>55,"name"=>"diane","boss"=>"rox"],
11=>["id"=>4,"name"=>"bideo","boss"=>"julia"]
];
$other_variable=[
1=>["picture1"=>["name"=>"zee","id"=>4],"picture2"=>["name"=>"izzy","id"=>1]],
2=>["picture1"=>["name"=>"foo","id"=>55],"picture2"=>["name"=>"ido","id"=>44]],
3=>["picture1"=>["name"=>"wheez","id"=>87],"picture2"=>["name"=>"ardu","id"=>9]]
];
array_walk($category,function(&$v,$k,$ov){$v['other_variable']=current($ov);},$other_variable);
var_export($category);
Output:
array (
37 =>
array (
'id' => 1,
'name' => 'joe',
'boss' => 'kev',
'other_variable' =>
array (
'picture1' =>
array (
'name' => 'zee',
'id' => 4,
),
'picture2' =>
array (
'name' => 'izzy',
'id' => 1,
),
),
),
73 =>
array (
'id' => 55,
'name' => 'diane',
'boss' => 'rox',
'other_variable' =>
array (
'picture1' =>
array (
'name' => 'zee',
'id' => 4,
),
'picture2' =>
array (
'name' => 'izzy',
'id' => 1,
),
),
),
11 =>
array (
'id' => 4,
'name' => 'bideo',
'boss' => 'julia',
'other_variable' =>
array (
'picture1' =>
array (
'name' => 'zee',
'id' => 4,
),
'picture2' =>
array (
'name' => 'izzy',
'id' => 1,
),
),
),
)
Late Edit:
Additional methods that modify the $other_variable array (effectively empty it when the iterative process resolves) include:
$category=array_map(function($v)use(&$other_variable){
return $v+=['other_variable'=>array_shift($other_variable)];
},$category);
and
foreach($category as &$value){
$value["other_variable"]=array_shift($other_variable);
}
Obviously, these methods should only be used if you do not intend to use $other_variable down script or you are going to declare a copy of the array for later use.
I have these three arrays:
Array
(
[1] => sadsad#fsdf.fgh
[2] => rtt#RERT.FDG
[3] => WQEWQ#fgdg.h
)
Array
(
[1] =>
[2] => 4234235
[3] =>
)
Array
(
[2] => 1
)
And I want to generate this output:
Array
(
[1] => array(
[0] => sadsad#fsdf.fgh
)
[2] => array(
[0] => rtt#RERT.FDG
[1] => 4234235
[2] => 1
)
[3] => array(
[0] => WQEWQ#fgdg.h
)
)
I need some assistance because I already researched array_merge_recursive() and array_merge(), but I can't get the correct result.
If I need to use foreach() what must I do to merge these 3 arrays.
Wrote a little script:
$a = array
(
1=>"sadsad#fsdf.fgh",
2=>"rtt#RERT.FDG",
3=>"WQEWQ#fgdg.h",
);
$b = array
(
2 => 4234235
);
$c = array
(
2 => 1
);
$arrayKeys = array_unique(
array_merge(
array_keys($a),
array_keys($b),
array_keys($c)
)
);
$d = array_combine(
$arrayKeys,
array_fill(
0,
count($arrayKeys),
array()
)
);
foreach($a as $key => $value) {
if(!empty($a[$key])) {
$d[$key][] = $a[$key];
}
if(!empty($b[$key])) {
$d[$key][] = $b[$key];
}
if(!empty($c[$key])) {
$d[$key][] = $c[$key];
}
}
var_dump($d);
Also if you want to you can merge together the arrays using the variable names only
//names of the variables to merge together
$arrayVariableNames = array("a","b","c");
//merging array keys together
$arrayKeys = array();
foreach($arrayVariableNames as $variableName) {
$arrayKeys = array_merge(
$arrayKeys,
array_keys(${$variableName})
);
}
$arrayKeys = array_unique($arrayKeys);
//initialize the result array with empty arrays
$resultArray = array_combine(
$arrayKeys,
array_fill(
0,
count($arrayKeys),
array()
)
);
//loop through all the keys and add the elements from all the arrays
foreach($resultArray as $key => &$value) {
foreach($arrayVariableNames as $variableName) {
if(!empty(${$variableName}[$key])) {
$value[] = ${$variableName}[$key];
}
}
}
As you have no doubt discovered, array_merge_recursive() stubbornly smashes all numeric or "numeric string" keys into a 1-dimensional array. To avoid this behavior, you need to cast each of your arrays' initial keys as strings in a way that will not be assumed to be a number by array_merge_recursive().
Additionally you want to filter out all elements that have empty values.
I initially wrote a one-liner that performed the key re-casting then filtered the values, but it is less efficient that way. For your case, you should only use array_filter() on arrays that may possibly contain empty values.
Input Arrays:
$a=[1=>"sadsad#fsdf.fgh",2=>"rtt#RERT.FDG",3=>"WQEWQ#fgdg.h"];
$b=[1=>"",2=>"4234235",3=>""];
$c=[2=>1];
Code:
// remove empty values from all arrays that may have them
$b=array_filter($b,'strlen');
// for all arrays, cast numeric keys to string by prepending with a space
function addK($v){return " $v";}
$a=array_combine(array_map('addK',array_keys($a)),$a);
$b=array_combine(array_map('addK',array_keys($b)),$b);
$c=array_combine(array_map('addK',array_keys($c)),$c);
// merge arrays recursively
$merged=array_merge_recursive($a,$b,$c);
// cast keys back to numeric
$merged=array_combine(array_map('trim',array_keys($merged)),$merged);
// force all top-level elements to be arrays
foreach($merged as $k=>$v){
if(is_string($merged[$k])){$merged[$k]=[$v];}
}
var_export($merged);
Output:
array (
1 => array (
0 => 'sadsad#fsdf.fgh',
),
2 => array (
0 => 'rtt#RERT.FDG',
1 => '4234235',
2 => 1,
),
3 => array (
0 => 'WQEWQ#fgdg.h',
),
)
For readers who want to know the difference when array_merge_recursive() is run with no preparation:
array (
0 => 'sadsad#fsdf.fgh',
1 => 'rtt#RERT.FDG',
2 => 'WQEWQ#fgdg.h',
3 => '',
4 => '4234235',
5 => '',
6 => 1,
)
Notice the 1d array and the re-indexed keys? ...totally useless for the OP.
Finally, for anyone who wants to re-cast the keys to all arrays and would like to make my process more DRY, there may be an opportunity to set up a variadic function or similar. I merely didn't bother to pursue the notion because I didn't want to make my answer anymore complex and it is not a terrible amount of Repeating Myself.
Maybe the title can not explain my question ,please see my example :
I have an multi-dimension array like this :
Array
(
[0] => Array
(
[name] => 'A'
[ec_dest_name] => 楽天testuser_998
),
[1] => Array
(
[name] => 'A'
[ec_dest_name] => 楽天testuser_998
),
[2] => Array
(
[name] => 'B'
[ec_dest_name] => 楽天testuser_998
),
[3] => Array
(
[name] => 'C'
[ec_dest_name] => 楽天testuser_998
)
)
I want to count the element by key name , it mean that I want to return an array like :
Array ('A' => 2 , 'B'=>1, 'C'=>1)
Any quick way to accomplish that , I could loop array and count but I think it is not a good idea
Thank in advanced
You can use array_count_values & array_column togather -
$counts = array_count_values(array_column($your_array, 'name'));
Output
array(3) {
["A"]=>
int(2)
["B"]=>
int(1)
["C"]=>
int(1)
}
Demo
As Mark Baker suggested for older PHP versions -
$counts = array_count_values(
array_map(function($value) {
return $value['name'];
}, $your_array)
);
You may as well do that with 2 Loops as shown below. You might test this also HERE.
<?php
$arrSections = array();
$arrCounts = array();
$arrMain = array(
array(
'name' => "A",
'ec_dest_name' => "楽天testuser_998",
),
array(
'name' => "A",
'ec_dest_name' => "楽天testuser_998",
),
array(
'name' => "B",
'ec_dest_name' => "楽天testuser_998",
),
array(
'name' => "C",
'ec_dest_name' => "楽天testuser_998",
),
);
// BUNDLE ARRAYS WITH SIMILAR name INTO ONE GROUP
// THUS CREATING A MULTI-DIMENSIONAL ARRAY WHOSE MAIN KEYS CORRESPOND TO
// THE name OF THE MEMBER ARRAYS IN THE GROUP.
foreach($arrMain as $iKey=>$subMain){
$name = $subMain['name'];
if(!array_key_exists($name, $arrSections)) {
$arrSections[$name] = array();
}
$arrSections[$name][] = $subMain;
}
// FETCH THE COUNTS OF EACH GROUP AND MAKE AN ARRAY OUT OF IT...
foreach($arrSections as $k=>$v){
$arrCounts[$k] = count($v);
}
var_dump($arrCounts);
//OUTPUTS::
array (size=3)
'A' => int 2
'B' => int 1
'C' => int 1
Starting Point
I have a multi-dimensional array, like the follow example:
$array = array (
'role_1' =>
array (
0 => 'value_2',
1 => 'value_3',
),
'role_2' =>
array (
0 => 'value_1',
1 => 'value_2',
),
'role_3' =>
array (
0 => 'value_2',
1 => 'value_3',
),
)
Goal
I like to loop about the sub-arrays to get only the intersection. The array was created dynamically, can have a lot of sub-arrays role_[x] and also a lot of key/value inside the sub-arrays. The key is not necessary, only the value. The key is also a count, not a string.
As result I like to get in this example this small array.
$array = array( 'value_2' )
The index, "the array-name", like role_1 of the sub-arrays is not more relevant after intersection. Important for me in the result is the values, only the values there are existed in each sub-array.
Try
I had tried with the source, but I think it is possible much simpler.
$value_stack = array();
$result = array();
$i = 0;
foreach( $settings_ as $role => $values ) {
foreach( $values as $value ){
if( in_array( $value,$value_stack ) || $i === 0 ) {
$result[ $role ][] = $value;
}
$value_stack[] = $value;
}
$i++;
};
The merge of this multi array result should run with a array_merge in a loop.
Thanks for your time.
You can use array_intersect to cover the dynamic $data as such:
$data = array (
'role_1' =>
array (
0 => 'value_2',
1 => 'value_3',
),
'role_2' =>
array (
0 => 'value_1',
1 => 'value_2',
),
'role_3' =>
array (
0 => 'value_2',
1 => 'value_3',
)
);
$result = call_user_func_array('array_intersect', $data);
call_user_func_array will help spread the elements of your array as parameters inside array_intersect.
You should be able to do
call_user_func_array('array_intersect', $array_of_arrays)
This will pass each element of your array of arrays as an argument to array_intersect, which takes a variable number of arrays as arguments and returns their intersection.
array_intersect work for this:
$data = array (
'role_1' =>
array (
0 => 'value_2',
1 => 'value_3',
),
'role_2' =>
array (
0 => 'value_1',
1 => 'value_2',
),
'role_3' =>
array (
0 => 'value_2',
1 => 'value_3',
)
);
$result = array_intersect($data['role_1'], $data['role_2'], $data['role_3']);
print_r($result);
result :
Array ( [0] => value_2 )
As of PHP 5.6+ the splat/spread operator can be used to unpack the arguments in a call to array_intersect(). In order to remove the non-numeric keys from the array, pass $array to a call to array_values().
$result = array_intersect(...array_values($array));
See a demonstration in this playground example.
I have the following array, which I would like to reindex so the keys are reversed (ideally starting at 1):
Current array (edit: the array actually looks like this):
Array (
[2] => Object
(
[title] => Section
[linked] => 1
)
[1] => Object
(
[title] => Sub-Section
[linked] => 1
)
[0] => Object
(
[title] => Sub-Sub-Section
[linked] =>
)
)
How it should be:
Array (
[1] => Object
(
[title] => Section
[linked] => 1
)
[2] => Object
(
[title] => Sub-Section
[linked] => 1
)
[3] => Object
(
[title] => Sub-Sub-Section
[linked] =>
)
)
If you want to re-index starting to zero, simply do the following:
$iZero = array_values($arr);
If you need it to start at one, then use the following:
$iOne = array_combine(range(1, count($arr)), array_values($arr));
Here are the manual pages for the functions used:
array_values()
array_combine()
range()
Why reindexing? Just add 1 to the index:
foreach ($array as $key => $val) {
echo $key + 1, '<br>';
}
Edit After the question has been clarified: You could use the array_values to reset the index starting at 0. Then you could use the algorithm above if you just want printed elements to start at 1.
This will do what you want:
<?php
$array = array(2 => 'a', 1 => 'b', 0 => 'c');
array_unshift($array, false); // Add to the start of the array
$array = array_values($array); // Re-number
// Remove the first index so we start at 1
$array = array_slice($array, 1, count($array), true);
print_r($array); // Array ( [1] => a [2] => b [3] => c )
?>
You may want to consider why you want to use a 1-based array at all. Zero-based arrays (when using non-associative arrays) are pretty standard, and if you're wanting to output to a UI, most would handle the solution by just increasing the integer upon output to the UI.
Think about consistency—both in your application and in the code you work with—when thinking about 1-based indexers for arrays.
You can reindex an array so the new array starts with an index of 1 like this;
$arr = array(
'2' => 'red',
'1' => 'green',
'0' => 'blue',
);
$arr1 = array_values($arr); // Reindex the array starting from 0.
array_unshift($arr1, ''); // Prepend a dummy element to the start of the array.
unset($arr1[0]); // Kill the dummy element.
print_r($arr);
print_r($arr1);
The output from the above is;
Array
(
[2] => red
[1] => green
[0] => blue
)
Array
(
[1] => red
[2] => green
[3] => blue
)
Well, I would like to think that for whatever your end goal is, you wouldn't actually need to modify the array to be 1-based as opposed to 0-based, but could instead handle it at iteration time like Gumbo posted.
However, to answer your question, this function should convert any array into a 1-based version
function convertToOneBased( $arr )
{
return array_combine( range( 1, count( $arr ) ), array_values( $arr ) );
}
EDIT
Here's a more reusable/flexible function, should you desire it
$arr = array( 'a', 'b', 'c' );
echo '<pre>';
print_r( reIndexArray( $arr ) );
print_r( reIndexArray( $arr, 1 ) );
print_r( reIndexArray( $arr, 2 ) );
print_r( reIndexArray( $arr, 10 ) );
print_r( reIndexArray( $arr, -10 ) );
echo '</pre>';
function reIndexArray( $arr, $startAt=0 )
{
return ( 0 == $startAt )
? array_values( $arr )
: array_combine( range( $startAt, count( $arr ) + ( $startAt - 1 ) ), array_values( $arr ) );
}
A more elegant solution:
$list = array_combine(range(1, count($list)), array_values($list));
The fastest way I can think of
array_unshift($arr, null);
unset($arr[0]);
print_r($arr);
And if you just want to reindex the array(start at zero) and you have PHP +7.3 you can do it this way
array_unshift($arr);
I believe array_unshift is better than array_values as the former does not create a copy of the array.
Changelog
Version
Description
7.3.0
This function can now be called with only one parameter. Formerly, at least two parameters have been required.
-- https://www.php.net/manual/en/function.array-unshift.php#refsect1-function.array-unshift-changelog
$tmp = array();
foreach (array_values($array) as $key => $value) {
$tmp[$key+1] = $value;
}
$array = $tmp;
It feels like all of the array_combine() answers are all copying the same "mistake" (the unnecessary call of array_values()).
array_combine() ignores the keys of both parameters that it receives.
Code: (Demo)
$array = [
2 => (object)['title' => 'Section', 'linked' => 1],
1 => (object)['title' => 'Sub-Section', 'linked' => 1],
0 => (object)['title' => 'Sub-Sub-Section', 'linked' => null]
];
var_export(array_combine(range(1, count($array)), $array));
Output:
array (
1 =>
(object) array(
'title' => 'Section',
'linked' => 1,
),
2 =>
(object) array(
'title' => 'Sub-Section',
'linked' => 1,
),
3 =>
(object) array(
'title' => 'Sub-Sub-Section',
'linked' => NULL,
),
)
If you are not trying to reorder the array you can just do:
$array = array_reverse( $array );
and then call it once more to get it back to the same order:
$array = array_reverse( $array );
array_reverse() reindexes as it reverses. Someone else showed me this a long time ago. So I can't take credit for coming up with it. But it is very simple and fast.
The result is an array with indexed keys starting from 0. https://3v4l.org/iQgVh
array (
0 =>
(object) array(
'title' => 'Section',
'linked' => 1,
),
1 =>
(object) array(
'title' => 'Sub-Section',
'linked' => 1,
),
2 =>
(object) array(
'title' => 'Sub-Sub-Section',
'linked' => NULL,
),
)
Here's my own implementation. Keys in the input array will be renumbered with incrementing keys starting from $start_index.
function array_reindex($array, $start_index)
{
$array = array_values($array);
$zeros_array = array_fill(0, $start_index, null);
return array_slice(array_merge($zeros_array, $array), $start_index, null, true);
}