I have two arrays:
$course = Array ( [6] => 24 [0] => 20 [1] => 14 ) // etc
With the key being the link to the next array:
Array (
[0] => Array ( [course_id] => 1 [course_name] => Appetizer )
[1] => Array ( [course_id] => 2 [course_name] => Breakfast )
) //etc
I basically want to add the course_name to the first array on course_id = keyso that it I can print out '1', 'Appetizer', '14'
Sorry if Ive explained this badly but its late and merging arrays frazzles my brain at this time!
5.3's closures combined with the various native array iteration functions make this in to a pretty painless process:
<?php
// where $key is a course_id and $value is the associated course's next course
$nextCourse = array(6 => 24, 0 => 20, 1 => 14);
// course definitions
$courses = array(
0 => array("course_id" => 1, "course_name" => 'Appetizer'),
1 => array("course_id" => 2, "course_name" => 'Breakfast')
);
// loop through and add a next_course reference if one exists in $nextCourse map
foreach($courses as &$course) {
if (isset($nextCourse[$course["course_id"]])) {
$course["next_course"] = $nextCourse[$course["course_id"]];
}
}
// $courses is now the same as the var dump at the end
/**
* A bit of 5.3 proselytism with native array functions and closures, which is
* an overly complex answer for this particular question, but a powerful pattern.
*
* Here we're going to iterate through the courses array by reference and
* make use of a closure to add the next course value, if it exists
*
* array_walk iterates over the $courses array, passing each entry in
* the array as $course into the enclosed function. The parameter is
* marked as pass-by-reference, so you'll get the modifiable array instead
* of just a copy (a la pass-by-value). The enclosure function requires
* the 'use' keyword for bringing external variables in to scope.
*/
array_walk($courses, function(&$course) use ($nextCourse) {
/**
* We check to see if the current $course's course_id is a key in the
* nextCourse link mapping, and if it is we take the link mapping
* value and store it with $course as its next_course
*/
if (isset($nextCourse[$course["course_id"]])) {
$course["next_course"] = $nextCourse[$course["course_id"]];
}
});
var_dump($courses);
/**
Output:
array(2) {
[0]=>
array(3) {
["course_id"]=>
int(1)
["course_name"]=>
string(9) "Appetizer"
["next_course"]=>
int(14)
}
[1]=>
array(2) {
["course_id"]=>
int(2)
["course_name"]=>
string(9) "Breakfast"
}
}
*/
Related
I am simply trying to turn this:
Array
(
[0] => 20200330
[1] => 20200329
[2] => 20200328
)
Into this and I am having an extremely hard time
Array
(
20200330,
0200329,
20200328,
)
All arrays in PHP have a unique key for each value within that array.
By default they are 0, 1, 2, 3, etc unless you explicitly set them (e.g. $a = ['key' => 1234];).
It is possible to "remove" keys (set to default without impacting the order) through the use of the array_values() function:
$a = ['a' => 123, 'b' => 321];
$a = array_values($a);
print_r($a); // [0 => 123, 1 => 321]
But it is not possible to entirely remove the keys from an array.
Arrays are by default associated with numbers starting from 0
<?php
$arr=array("String1","String2","Something else");
var_dump($arr);
?>
Output will be:
array(3) {
[0]=>
string(7) "String1"
[1]=>
string(7) "String2"
[2]=>
string(14) "Something else"
}
So if you want to access element of array you type $arr[index] and index is number by default
This question already has an answer here:
How right replace value element in array?
(1 answer)
Closed 5 years ago.
I am using WordPress and have a custom post type setup with a set number of options, with the basic breakdown being something like this:
30" Round Table
Buffet
Cocktail
Dessert
Banquet Table
Buffet
Gift
DJ Table
I am trying to collect all items into a grouped collection, for use with <optgroup /> to show all tables under Buffet, all under Cocktail, etc. like so:
Buffet
30" Round Table
Banquet Table
Cocktail
Banquet Table
[and so on]
The PHP issue I'm running into is I have a master array that has all the types (buffet, cocktail, etc.) along with an (initially) empty array element called tables for me to add all the tables that support that specific type. Retrieving the options from ACF works fine, as does retrieving the individual posts from WordPress, so this is strictly a packaging issue to kick back as JSON. Here is a code example:
//gets the field associated with the different table types (Buffet, Cocktail, etc.)
$field = get_field_object('field_577ff065e6699');
$list = array();
//create the base array
foreach ($field["choices"] as $type) {
$list[] = array
(
"type" => $type, //Buffet, Cocktail, etc.
"tables" => array() //placeholder to add WP items
);
}
//now get all tables
$tablesQuery = new WP_Query( array( 'post_type' => 'table', 'posts_per_page' => -1, 'order' => 'ASC' ) );
//loop through and add the table(s) to their categories
while ( $tablesQuery->have_posts() ) : $tablesQuery->the_post();
//gets the types supported by this table
$tableTypes = get_field('options');
//individual types
foreach ($tableTypes as $tableType) {
//all types
foreach ($list as $supportedType) {
//see if there is a match and add it
if ($tableType == $supportedType["type"]) {
//add to the array since it matches
$table = array
(
"name" => get_the_title(),
"sqft" => (int)get_field('square_footage'),
"seats" => (int)get_field('seats')
);
array_push($supportedType["tables"], $table);
//shows the single table above, but nothing prior
print_r($supportedType);
}
}
}
endwhile;
wp_reset_postdata();
//all "tables" arrays are empty here
var_dump($list);
The output of print_r($supportedType) above ends up showing all data, however the tables entry is always only one element when it should be multiple:
Array
(
[type] => Buffet
[tables] => Array
(
[0] => Array
(
[name] => 30” Round Bistro/Cocktail Table
[sqft] => 42
[seats] => 2
)
)
)
Array
(
[type] => Cake
[tables] => Array
(
[0] => Array
(
[name] => 30” Round Bistro/Cocktail Table
[sqft] => 42
[seats] => 2
)
)
)
[.. snip ..]
Finally, when I do the var_dump($list) at the end, all of the types show up but their associated tables arrays are all empty:
array(11) {
[0]=>
array(2) {
["type"]=>
string(6) "Buffet"
["tables"]=>
array(0) {
}
}
[1]=>
array(2) {
["type"]=>
string(4) "Cake"
["tables"]=>
array(0) {
}
}
This has me completely lost, even though it has to be something incredibly basic that I'm missing. Any ideas why tables is empty, despite using array_push on the looped item? I also tried $supportedType["tables"][] = $table, but that has the same effect.
I think you're working with a copy of the array inside this foreach: foreach ($list as $supportedType) {
Try changing it to
foreach ($list as $key => $supportedType) {
...
// this operates on the copy
// array_push($supportedType["tables"], $table);
// operate on the original instead
array_push($list[$key]["tables"], $table);
...
}
I have multidimensional array $items and I need to search it and then create new array(s).
This array is generated at the end of check-up in e-shop I'm trying to build, so array can be of random length. I need to create to create new array for every new supplier_id so I can send data to each and every one of them apart.
I already have code for making order but now it just takes all data at once. So in this particular example I'm expecting 3 multidimensional arrays that I can run trough my create_order code.
I know there are many threads talking about multidimensional arrays but none that I can understand enough to apply it in my case. Thanks very much for help.
Here is what $items may look like
array (4)
id => 36
count => 1
product => Nette\Database\Table\ActiveRow #7c60
table private => Nette\Database\Table\Selection #739c
data private => array (3)
product_id => 36
price => 219.0
supplier_id => 3
dataRefreshed private => FALSE
names => array (1)
en => "Product 1" (9)
array (4)
id => 180
count => 1
product => Nette\Database\Table\ActiveRow #938b
table private => Nette\Database\Table\Selection #a5f0
data private => array (3)
product_id => 180
price => 375.0
supplier_id => 4
dataRefreshed private => FALSE
names => array (1)
en => "Product 2" (9)
array (4)
id => 309
count => 1
product => Nette\Database\Table\ActiveRow #4c67
table private => Nette\Database\Table\Selection #8f56
data private => array (3)
product_id => 309
price => 40.0
supplier_id => 5
dataRefreshed private => FALSE
names => array (1)
en => "Product 3" (9)
So after few hours of digging I was amazed how easily it can by done
// searching for all unique supplier_id
$uniqueID = array();
foreach ($items as $item) {
if (!in_array($item['product']['supplier_id'], $uniqueID)) {
array_push($uniqueID, $item['id'] = $item['product']['supplier_id']);
}
}
// visual check of all unique *supplier_id*
dump($uniqueID);
// creation of array where I'm going to insert all necessary data
foreach ($uniqueID as $array) {
$defined_array = [];
// visual check for debugging purposes
dump("start");
// creating multiarray for every unique *supplier_id* and inserting data
foreach ($items as $item) {
if($item['product']['supplier_id'] == $array) {
$defined_array[] = $item;
}
}
// final check of all arrays + debug check for end --
// at the end this block is replaced by *create_order* code
foreach ($defined_array as $array) {
dump($array);
}
dump("end");
}
At the end I hope it will help to someone at least.
This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 6 months ago.
Array
(
[0] => Array
(
[color] => Brown
)
[1] => Array
(
[color] => Green
)
[2] => Array
(
[width] => 34
)
)
i need to make it like this
[color] => Array
(
[0] => green
[1] => brown
)
[width] => Array
(
[0] => 34
)
)
i am trying with all the array tools. But i cant make it like i want it.
This is fairly simple with array_column() (requires PHP >= 5.5.0):
$result = array[
'color' => array_column($arr, 'color'),
'width' => array_column($arr, 'width')
];
Live fiddle: https://eval.in/81746
If you do not know the keys beforehand, here is another solution using array_walk_recursive():
$result = [];
array_walk_recursive($arr, function($value, $key) use (&$result) {
if (!isset($result[$key])) {
$result[$key] = [];
}
$result[$key][] = $value;
});
Live fiddle: https://eval.in/81745
So you want to merge the arrays recursively... if only such an array_merge_recursive function existed... Why don't you try this:
$a = array(
array('colour' => 'green'),
array('colour' => 'blue'),
array('width' => 123)
);
$result = array();
foreach($a as $arr)
{
$result = array_merge_recursive($result, $arr);
}
var_dump($result);
That worked pretty darn well for me, as you can see for yourself here, too
True, in the given example width won't be an array, so you get:
array('colour' => array('green','blue'),'width' => 123);
If you need everything to be an array, then a dirty fix would be to use a cast:
foreach($result as $k => $v) $result[$k] = (array) $v;
Reassigning the $result values a second time, only casting them as an array ensures that all values will, evidently, be arrays. An array that is cast to an array will remain unchanged, just like (int) 1 still evaluates to 1. A primitive value (strings, integers, doubles,...) will be wrapped int an array, but an object will be transformed into an array, so be careful. If objects are likely to occur in this array:
foreach($result as $k => $v) $result[$k] = is_array($v) ? $v : array($v);
is probably the safer bet. However, I chose not to go for this approach as I still find it pretty tedious and silly to wrap everything up into an array, containing only 1 value...
For those of you with a strange preference for unmaintainable code, the following one-liner is a condensed, but notice free & working example of the same code:
foreach($a as $arr) $result = array_merge_recursive(isset($result) ? $result : array(), $arr);
This is as a response to Stuart Wakefield who suggested a one-liner using call_user_func_array, which is something I'll always oppose, for as long as I live and breathe, BTW...
I guess this should do it, especially if you don't know what keys you will have:
foreach ($original_array as $val1)
foreach ($val1 as $key2=>$val2)
$merged_array[$key2][] = $val2;
just use foreach like below --
arrayName = your original array --
foreach($arrayName as $newArr){
if($newArr['color']){
$tempArr['color'][] = $newArr['color'];
}
if($newArr['width']){
$tempArr['width'][] = $newArr['width'];
}
}
Try using array_merge_recursive OR array_column
Building upon Elias's array_merge_recursive answer, the following introduces a small fix to turn single item merge into an array:
/* This version uses the function array_merge_recursive to collect
* all of the values for the nested arrays by key
*
* #see http://willem.stuursma.name/2011/09/08/parallel-array_map-with-hiphop/
* #see http://willem.stuursma.name/2010/11/22/a-detailed-look-into-array_map-and-foreach/
* for why for loops are better than array_map in general
*/
$result = array_map(function($item) {
/* The array_merge_recursive function doesn't add
* values to an array if there was only one found
* if the item isn't an array, make it an array
*/
return is_array($item) ? $item : array($item);
/* Calls the array_merge_recursive function applying all of
* the nested arrays as parameters.
*
* #see http://php.net/array_merge_recursive
* #see http://www.php.net/call_user_func_array
*/
}, call_user_func_array('array_merge_recursive', $arr));
Produces:
Array
(
[color] => Array
(
[0] => green
[1] => brown
)
[width] => Array
(
[0] => 34
)
)
Instead of:
Array
(
[color] => Array
(
[0] => green
[1] => brown
)
[width] => 34
)
Alternatively, a dynamic approach to ComFreek's array_column solution.
This gives you the array of the keys:
/* Gets the keys of the nested arrays as a single array of keys by first
* mapping the nested arrays to an array of keys they contain and then
* by merging these arrays and killing duplicates
*
* #see http://php.net/function.array-unique
* #see http://www.php.net/call_user_func_array
* #see http://www.php.net/array_merge
* #see http://www.php.net/array_map
*/
$keys = array_unique(call_user_func_array('array_merge', array_map(function($item) {
/* Replaces the nested array of keys and values with an array
* of keys only in the mapped array
*
* #see http://www.php.net/array_keys
*/
return array_keys($item);
}, $arr)));
As:
Array
(
[0] => color
[1] => width
)
Which can be used with this snippet:
/* Combines the array of keys with the values from the nested
* arrays.
*
* #see http://php.net/array_combine
* #see http://www.php.net/manual/en/function.array-map.php
*/
$result = array_combine($keys, array_map(function($key) use($arr) {
/* Collects the values from the nested arrays
*
* #see http://php.net/array_column
*/
return array_column($arr, $key);
}, $keys));
To create the desired output:
Array
(
[color] => Array
(
[0] => green
[1] => brown
)
[width] => Array
(
[0] => 34
)
)
Note: functional calls can be beneficial in most languages over an imperative style although it does require a shift mentally. Functional patterns open up the possibilities of low level optimizations that otherwise wouldn't be possible. Array map, for example, could be executed in parallel, whereas a for loop cannot, the for loop will always have a restriction that it must execute sequentially.
When retrieving a hierarchical structure from MySQL (table with one ID column and one PARENT column signifying the hierarchical relationships), I map the result into an enumerated array as follows (for this example the numbers are arbitrary):
Array ( [3] => Array ( [7] => Array () ), [7] => Array ( [8] => Array () ) )
Notice 3 is the parent of 7, and 7 is the parent of 8 (this could go on and on; and any parent could have multiple children).
I wanted to shrink this array into a nested multidimensional array as follows:
Array ( [3] => Array ( [7] => Array ( [8] => Array () ) ) )
That is, each NEW id is automatically assigned an empty array. Regardless, any ID's children will be pushed into their parent's array.
Take a look at the following illustration for further clarification:
alt text http://img263.imageshack.us/img263/4986/array.gif
This will probably result in a complicated recursive operation, since I always have to check whether a parent with any certain ID already exists (and if so, push the value into its array).
Is there a built-in php function that can assist me with this? Do you have any idea as to how to go about constructing this? For what it's worth I'm using this to built a navigation bar in wordpress (which can contain categories, subcategories, posts... essentially anything).
The idea is that you keep an auxiliary array with all the nodes (parent and child) you find. The values of this arrays are references that back your result.
This builds the tree in linear time (array_key_exists does a hash table lookup, which is on average O(1)):
//table contains (id, parent)
$orig = array(
11 => 8,
7 => 3,
8 => 7,
99 => 8,
16 => 8,
);
$childrenTable = array();
$result = array();
foreach ($orig as $n => $p) {
//parent was not seen before, put on root
if (!array_key_exists($p, $childrenTable)) {
$childrenTable[$p] = array();
$result[$p] = &$childrenTable[$p];
}
//child was not seen before
if (!array_key_exists($n, $childrenTable)) {
$childrenTable[$n] = array();
}
//root node has a parent after all, relocate
if (array_key_exists($n, $result)) {
unset($result[$n]);
}
$childrenTable[$p][$n] = &$childrenTable[$n];
}
unset($childrenTable);
var_dump($result);
gives
array(1) {
[3]=>
array(1) {
[7]=>
array(1) {
[8]=>
array(3) {
[11]=>
array(0) {
}
[99]=>
array(0) {
}
[16]=>
array(0) {
}
}
}
}
}
EDIT: unset $childrenTable in the end to clear reference flags. In practice, you will probably want to do the operation inside a function anyway.
This question and it's answers should be helpful to you: turn database result into array.
Be sure to read the PDF presentation by #Bill Karwin, specifically the topics regarding the Closure table.