Related
For four days I am trying to figure out how to solve this, as well as googling it, and was no luck
The problem is that I needed to loop through a nested array (for unknown deep) and keep the top-level keys (as a prefix to the last value) as long as I am still going deep, and then start over (the prefix need to reset) once it started a new path.
I want to generate complete addresses from this array.
$arr = [
"buildings" => [
"group1" => [
"b1" => [1,2,3,4],
"b2" => [1,2,3]
],
"group2" => [
"b1" => [1,2]
]
],
"villas" =>[
"group1" => [
"v1" => [1,2],
"v2" => [1]
],
"group2" => [
"v1" => [1],
"v2" => [1]
],
"group3" => [
"v1" => [1]
],
]
];
This is the needed output
buildings/group1/b1/1
buildings/group1/b1/2
buildings/group1/b1/3
buildings/group1/b1/4
buildings/group1/b2/1
buildings/group1/b2/2
buildings/group1/b2/3
buildings/group2/b1/1
buildings/group2/b1/2
villas/group1/v1/1
villas/group1/v1/2
villas/group1/v2/1
villas/group2/v1/1
villas/group2/v2/1
villas/group3/v1/1
I tried this function but also it didn't bring the wanted results
function test($array, $path = ""){
foreach ($array as $key => $value) {
if (is_array($value)){
$path .= $key."/";
test($value, $path);
} else {
echo $path.$value."<br>";
}
}
}
test($arr);
UPDATE
I understood where was my mistake and I wanted to share with you my modification to my method after I fixed it.
function test($array, $path = ""){
foreach ($array as $key => $value) {
if (is_array($value)){
test($value, $path . $key . '/');
} else {
echo $path.$value."<br>";
}
}
}
And thanks to #Kai Steinke he's method is way better than mine, and here is some improvements just to make it look better.
function flatten(array $array, array $flattened = [], string $prefix = ''): array
{
foreach ($array as $key => $value) {
if (is_array($value)) {
$flattened = array_merge( flatten($value, $flattened, $prefix . $key . '/'));
continue;
}
$flattened[] = $prefix . $value;
}
return $flattened;
}
Here you go:
function flatten($arr, $prefix = '') {
$result = [];
foreach ($arr as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, flatten($value, $prefix . $key . '/'));
} else {
$result[] = $prefix . $value;
}
}
return $result;
}
// Usage
print_r(flatten($arr))
Returns an Array:
Array (
[0] => buildings/group1/b1/1
[1] => buildings/group1/b1/2
[2] => buildings/group1/b1/3
[3] => buildings/group1/b1/4
[4] => buildings/group1/b2/1
[5] => buildings/group1/b2/2
[6] => buildings/group1/b2/3
[7] => buildings/group2/b1/1
[8] => buildings/group2/b1/2
[9] => villas/group1/v1/1
[10] => villas/group1/v1/2
[11] => villas/group1/v2/1
[12] => villas/group2/v1/1
[13] => villas/group2/v2/1
[14] => villas/group3/v1/1
)
Build and preserve the path using all encountered keys until arriving at a deep non-array value, then append the value to the string, and push the full path into the result array.
Code: (Demo)
function flatten(array $array, string $path = ''): array
{
$result = [];
foreach ($array as $k => $v) {
array_push(
$result,
...(is_array($v) ? flatten($v, "$path$k/") : ["$path$v"])
);
}
return $result;
}
var_export(flatten($array));
A slightly related answer where a slash-delimited string was built as the hierarchical path to a search value.
I am using Spout Excel reader to read Excel files from php code and saving into a multidimensional array in PHP variable,Array looks like this
$array = [
[
'id[0]' => 'BX-78',
'Name[0]' => 'XXX',
'Address[0]' => 'YUUSATD'
],
[
'id[1]' => 'BX-79',
'Name[1]' => 'YYY',
'Address[1]' => 'DHJSHDJGY'
],
[
'id[2]' => 'BX-80',
'Name[2]' => 'ZZZ',
'Address[2]' => 'DDSDSDA'
]
[
'id[3]' => 'BX-78',
'Name[3]' => 'AAA',
'Address[3]' => 'FSDSDS'
][
'id[4]' => 'BX-81',
'Name[4]' => 'XXX',
'Address[4]' => 'DSDSDSD'
]];
Now i want to show duplicate data from above array using two keys ['id'] and ['name'] if id repeats show as duplicate data,
If name repeats show that row as duplicate data if both are duplicate show as again duplicate row
Otherwise it is unique row.
I have tried using multidimensional array sorting but it is using only one key to match data in rows.
foreach ($arrExcelData as $v) {
if (isset($arrExcelData[$v[0]])) {
// found duplicate
continue;
}
// remember unique item
$arrExcelData3[$v[0]] = $v;
}
// if you need a zero-based array, otheriwse work with $_data
$arrExcelData2 = array_values($arrExcelData3);
Edited : Expected Output Result :
Matching Rows:
Id Name Address
-------------------------
BX-78 XXX YUUSATD
BX-78 AAA DDSDSDA
BX-81 XXX DSDSDSD`
If you want to list the duplicate values, I think the address of the second match should be FSDSDS as there is not item with name AAA and value DDSDSDA:
BX-78 AAA FSDSDS
If that is the case, what you could do is to first use a double foreach to mark the arrays that contain a duplicate id or name by for example adding a property named id and name except when the array is itself in the second loop.
After this loop, you can tell which arrays are the duplicate ones. Instead of using a corresponding index 0 as in id[0], I have used reset and next so it is not tied to these indexes.
To get the filtered result you could use array_reduce to check for the array keys and unset them.
For example:
foreach ($array as $index => $a) {
foreach ($array as $v) {
if ($v === $a) continue;
if (reset($v) === reset($a)) $array[$index]["id"] = "duplicate";
if (next($v) === next($a)) $array[$index]["name"] = "duplicate";
}
}
$array = array_reduce($array, function($carry, $item) {
if (array_key_exists("id", $item) || array_key_exists("name", $item)) {
unset($item["id"], $item["name"]);
$carry[] = $item;
}
return $carry;
}, []);
print_r($array);
Result
Array
(
[0] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
[1] => Array
(
[id[3]] => BX-78
[Name[3]] => AAA
[Address[3]] => FSDSDS
)
[2] => Array
(
[id[4]] => BX-81
[Name[4]] => XXX
[Address[4]] => DSDSDSD
)
)
See a php demo
I've this very pragmatic approach:
$spout_output = [
[
'id[0]' => 'BX-78',
'Name[0]' => 'XXX',
'Address[0]' => 'YUUSATD'
],
[
'id[1]' => 'BX-79',
'Name[1]' => 'YYY',
'Address[1]' => 'DHJSHDJGY'
],
[
'id[2]' => 'BX-80',
'Name[2]' => 'ZZZ',
'Address[2]' => 'DDSDSDA'
],
[
'id[3]' => 'BX-78',
'Name[3]' => 'AAA',
'Address[3]' => 'FSDSDS'
],
[
'id[4]' => 'BX-81',
'Name[4]' => 'XXX',
'Address[4]' => 'DSDSDSD'
]];
// store id to row, and name to row mappings.
// id and name will be keys, value will be an array of indexes of the array $spout_output
$id_to_rows = array();
$name_to_rows = array();
$duplicate_ids = array();
$duplicate_names = array();
foreach($spout_output as $row => $data)
{
$key_id = 'id['.$row.']';
$key_name = 'Name['.$row.']';
if(!isset($data[$key_id]))
continue;
$value_id = $data[$key_id];
$value_name = $data[$key_name];
if(!isset($id_to_rows[$value_id]))
{
$id_to_rows[$value_id] = array();
}
else
{
if(!isset($duplicate_ids[$value_id]))
{
$duplicate_ids[$value_id] = $id_to_rows[$value_id];
}
$duplicate_ids[$value_id][] = $row;
}
if(!isset($name_to_rows[$value_name]))
{
$name_to_rows[$value_name] = array();
}
else
{
if(!isset($duplicate_names[$value_name]))
{
$duplicate_names[$value_name] = $name_to_rows[$value_name];
}
$duplicate_names[$value_name][] = $row;
}
$id_to_rows[$value_id][] = $row;
$name_to_rows[$value_name][] = $row;
}
echo 'Duplicates:';
echo '<br>';
$shown_rows = array();
foreach($duplicate_ids as $id => $rows)
{
foreach($rows as $nr)
{
echo $id . '|' . $spout_output[$nr]['Name['.$nr.']'] . '|' . $spout_output[$nr]['Address['.$nr.']'];
echo '<br>';
$shown_rows[] = $nr;
}
}
foreach($duplicate_names as $name => $rows)
{
foreach($rows as $nr)
{
// if already shown above, skip this row
if(in_array($nr, $shown_rows))
continue;
echo $spout_output[$nr]['id['.$nr.']'] . '|' . $spout_output[$nr]['Name['.$nr.']'] . '|' . $spout_output[$nr]['Address['.$nr.']'];
echo '<br>';
$shown_rows[] = $nr;
}
}
Outputs:
Duplicates:
BX-78|XXX|YUUSATD
BX-78|AAA|FSDSDS
BX-81|XXX|DSDSDSD
I think your 'wanted output' contains an error in the address?
Anyway, with my code above I think you'll have enough mapped data to produce the output you want.
You could do something like this:
$dupes = [];
$current = [];
foreach ($array as $index => $entry) {
$idKey = "id[$index]";
$nameKey = "Name[$index]";
if (array_key_exists($entry[$idKey], $current)) {
$dupes[] = [$entry, $current[$entry[$idKey]]];
}
elseif (array_key_exists($entry[$nameKey], $current)) {
$dupes[] = [$entry, $current[$entry[$nameKey]]];
}
else {
$current[$entry[$idKey]] = $current[$entry[$nameKey]] = $entry;
}
}
print_r($dupes);
Which results in an array containing each set of duplicates (array of arrays):
Array
(
[0] => Array
(
[0] => Array
(
[id[3]] => BX-78
[Name[3]] => AAA
[Address[3]] => FSDSDS
)
[1] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
)
[1] => Array
(
[0] => Array
(
[id[4]] => BX-81
[Name[4]] => XXX
[Address[4]] => DSDSDSD
)
[1] => Array
(
[id[0]] => BX-78
[Name[0]] => XXX
[Address[0]] => YUUSATD
)
)
)
Demo here: https://3v4l.org/JAtNU
In case someone of you are searching unique values by key.
function unique_multidim_array($array, $key) {
$temp_array = array();
$i = 0;
$key_array = array();
foreach($array as $val) {
if (!in_array($val[$key], $key_array)) {
$key_array[$i] = $val[$key];
$temp_array[$i] = $val;
}
$i++;
}
return $temp_array;
}
This function just takes multidimensional array and key value of field you need.
Then takes value of given array one by one (smaller arrays).
Then traverses given array and looking if taken key-value pair matches with given key.
After that if taken key-value pair matches with given key function just inserts smaller array in temporary array (array with unique values).
Don't forget to increment indexes of arrays ($i).
Then return array you got (with unique values) after function ends work.
I am looking to group an array into subarrays based on its keys.
Sample Array
Array
(
[0] => Array
(
[a_id] => 1
[a_name] => A1
[b_id] => 1
[b_name] => B1
[c_id] => 1
[c_name] => C1
)
[1] => Array
(
[a_id] => 1
[a_name] => A1
[b_id] => 1
[b_name] => B1
[c_id] => 2
[c_name] => C2
)
[2] => Array
(
[a_id] => 1
[a_name] => A1
[b_id] => 2
[b_name] => B2
[c_id] => 3
[c_name] => C3
)
[3] => Array
(
[a_id] => 2
[a_name] => A2
[b_id] => 3
[b_name] => B3
[c_id] => 4
[c_name] => C4
)
)
I need this sample array to be converted into a JSON array of the following format:
Expected Output
[{
"a_id": 1,
"a_name": "A1",
"b_list": [{
"b_id": 1,
"b_name": "B1",
"c_list": [{
"c_id": 1,
"c_name": "C1"
}, {
"c_id": 2,
"c_name": "C2"
}]
}, {
"b_id": 2,
"b_name": "B2",
"c_list": [{
"c_id": 3,
"c_name": "C3"
}]
}]
}, {
"a_id": 2,
"a_name": "A2",
"b_list": [{
"b_id": 3,
"b_name": "B3",
"c_list": [{
"c_id": 4,
"c_name": "C4"
}]
}]
}]
I was able to group by a key using the code below.
$array = array(
array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "1","c_name" => "C1"),
array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "2","c_name" => "C2"),
array("a_id" => "1","a_name" => "A1","b_id" => "2","b_name" => "B2","c_id" => "3","c_name" => "C3"),
array("a_id" => "2","a_name" => "A2","b_id" => "3","b_name" => "B3","c_id" => "4","c_name" => "C4")
);
$return = array();
foreach($array as $val) {
$return[$val["a_id"]][] = $val;
}
print_r($return);
But my actual scenario involves grouping into sub arrays didn't worked.
Looking forward to see if there is an optimized way or useful function to get into my expected JSON response.
Note: I am looking into a generalized use case here . For example : a_list as countries,b_list as states and c_list as cities.
Man that is very specific use case for arrays. Well here is your solution.
$array = <YOUR SAMPLE ARRAY>
$output = [];
/*
* Nesting array based on a_id, b_id
*/
foreach ($array as $item) {
$aid = $item['a_id'];
$bid = $item['b_id'];
$cid = $item['c_id'];
if(!isset($output[$aid])){
$output[$aid] = [
'a_id' => $item['a_id'],
'a_name' => $item['a_name'],
'b_list' => [
$bid => [
'b_id' => $item['b_id'],
'b_name' => $item['b_name'],
'c_list' => [
$cid = [
'c_id' => $item['c_id'],
'c_name' => $item['c_name']
]
]
]
]
];
} else if (!isset($output[$aid]['b_list'][$bid])){
$output[$aid]['b_list'][$bid] = [
'b_id' => $item['b_id'],
'b_name' => $item['b_name'],
'c_list' => [
$cid => [
'c_id' => $item['c_id'],
'c_name' => $item['c_name']
]
]
];
} else if(!isset($output[$aid]['b_list'][$bid]['c_list'][$cid])) {
$output[$aid]['b_list'][$bid]['c_list'][$cid] = [
'c_id' => $item['c_id'],
'c_name' => $item['c_name']
];
} else {
// Do/Dont overrider
}
}
/*
* Removing the associativity from the b_list and c_list
*/
function indexed($input){
$output = [];
foreach ($input as $key => $item) {
if(is_array($item)){
if($key == 'b_list' || $key == 'c_list'){
$output[$key] = indexed($item);
} else {
$output[] = indexed($item);
}
} else {
$output[$key] = $item;
}
}
return $output;
}
$indexed = indexed($output);
print_r(json_encode($indexed, 128));
Interesting requirement there.
Here is my generalized solution that is also extendable.
function transform($array, $group=[
['a_id','a_name','b_list'],
['b_id','b_name','c_list'],
['c_id','c_name'],
]){
foreach($array as $a){
$r = &$result;
foreach($group as $g){
$x = &$r[$a[$g[0]]];
$x[$g[0]] = $a[$g[0]];
$x[$g[1]] = $a[$g[1]];
if(isset($g[2])) $r = &$x[$g[2]]; else break;
}
}
return transformResult($result);
}
function transformResult($result){
foreach($result as &$a)
foreach($a as &$b)
if(is_array($b)) $b = transformResult($b);
return array_values($result);
}
To extend this solution, all you have to do is modify the $group parameter,
either directly in the function declaration or by passing an appropriate value as the 2nd parameter.
Usage example:
echo json_encode(transform($array), JSON_PRETTY_PRINT);
This will return the same output assuming the same $array input in your example.
Now here is the code that works best in the given situation. I have created a similar situation and then explained the solution in detail.
Situation
The Order Form is multipage depending on the number of days served based on the package selected. Details of each package are stored in the database with the following fields:
package_id (Unique Field)
package_name (Name of the Package, e.g. Package A)
servings_count (Total Servings in a Day)
days_served (Number of Days Served in a Month)
In order to carry forward the selection of meals for each day and serving of that day to store as an Order in the database, I required a Multidimensional Array of PHP that can be defined/populated dynamically.
Expected output is something like:
Array
(
[Day 1] => Array
(
[meal_id_1] => Unique ID //to be replaced with user selection
[meal_code_1] => Meal Name //to be replaced with user selection
[meal_type_1] => Meal //prefilled based on the selected package
[meal_id_2] => Not Available //to be replaced with user selection
[meal_code_2] => 2 //to be replaced with user selection
[meal_type_2] => Meal //prefilled based on the selected package
)
[Day 2] => Array
(
[meal_id_1] => Unique ID //to be replaced with user selection
[meal_code_1] => Meal Name //to be replaced with user selection
[meal_type_1] => Meal //prefilled based on the selected package
[meal_id_2] => Not Available //to be replaced with user selection
[meal_code_2] => 2 //to be replaced with user selection
[meal_type_2] => Meal //prefilled based on the selected package
)
This above array has been created 100% dynamically based on the explained structure and number of servings and days. Below is the code with some explanation.
First, we have to declare two PHP Arrays.
$total_meals_array = []; //Primary, Multidimension Array
$meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
After doing this, run MySQL query to read packages from the database. Now based on the result, do the following:
$total_meals_array = []; //Primary, Multidimension Array
$meals_selected_array = []; //Meals Details Array to be used as primary array's key value.
if( $num_row_packages >= 1 ) {
while($row_packages = mysqli_fetch_array ($result_packages)) {
$package_id = $row_packages['package_id'];
$package_name = $row_packages['package_name'];
$servings_count = $row_packages['servings_count'];
$days_served = $row_packages['days_served'];
//this for loop is to repeat the code inside `$days_served` number of times. This will be defining our primary and main Multidimensional Array `$total_meals_array`.
for ($y = 1; $y <= $days_served; $y++) {
//once inside the code, now is the time to define/populate our secondary array that will be used as primary array's key value. `$i`, which is the meal count of each day, will be added to the key name to make it easier to read it later. This will be repeated `$meals_count` times.
for ($i = 1; $i <= $meals_count; $i++) {
$meals_selected_array["meal_id_" . $i] = "Unique ID";
$meals_selected_array["meal_code_" . $i] = "Meal Name";
$meals_selected_array["meal_type_" . $i] = "Meal";
}
//once our secondary array, which will be used as the primary array's key value, is ready, we will start defining/populating our Primary Multidimensional Array with Keys Named based on `$days_served`.
$total_meals_array["Day " . $y] = $meals_selected_array;
}
}
}
That's it! Our dynamic Multidimensional Array is ready and can be viewed by simply the below code:
print "<pre>";
print_r($total_meals_array);
print "</pre>";
Thank you everyone, specially #yarwest for being kind enough to answer my question.
Here is the code, you can use it for index from a_ to y_ deep. The innerest element is null, if you don't want it. Terminate the for loop before last element, then process last element seperately. You also can do some improvement on this code. Hope this helps.
<?php
$array = array(
array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "1","c_name" => "C1"),
array("a_id" => "1","a_name" => "A1","b_id" => "1","b_name" => "B1","c_id" => "2","c_name" => "C2"),
array("a_id" => "1","a_name" => "A1","b_id" => "2","b_name" => "B2","c_id" => "3","c_name" => "C3"),
array("a_id" => "2","a_name" => "A2","b_id" => "3","b_name" => "B3","c_id" => "4","c_name" => "C4")
);
$arrays = array_map(function($v){return array_chunk($v, 2, true);}, $array);
$result = [];
foreach($arrays as $value)
{
$ref = &$result;
$len = count($value);
$index = 0;
for(; $index < $len; $index++)
{
$arr = $value[$index];
$char = key($arr)[0];
$charAdd = chr(ord($char)+1);
$key = $arr[$char.'_id'].$arr[$char.'_name'];
$listKey = $charAdd.'_list';
foreach($arr as $k => $v)
{
$ref[$key][$k] = $v;
}
$ref = &$ref[$key][$listKey];
}
}
var_dump($result);
Output: the online live demo
ei#localhost:~$ php test.php
array(2) {
["1A1"]=>
array(3) {
["a_id"]=>
string(1) "1"
["a_name"]=>
string(2) "A1"
["b_list"]=>
array(2) {
["1B1"]=>
array(3) {
["b_id"]=>
string(1) "1"
["b_name"]=>
string(2) "B1"
["c_list"]=>
array(2) {
["1C1"]=>
array(3) {
["c_id"]=>
string(1) "1"
["c_name"]=>
string(2) "C1"
["d_list"]=>
NULL
}
["2C2"]=>
array(3) {
["c_id"]=>
string(1) "2"
["c_name"]=>
string(2) "C2"
["d_list"]=>
NULL
}
}
}
["2B2"]=>
array(3) {
["b_id"]=>
string(1) "2"
["b_name"]=>
string(2) "B2"
["c_list"]=>
array(1) {
["3C3"]=>
array(3) {
["c_id"]=>
string(1) "3"
["c_name"]=>
string(2) "C3"
["d_list"]=>
NULL
}
}
}
}
}
["2A2"]=>
array(3) {
["a_id"]=>
string(1) "2"
["a_name"]=>
string(2) "A2"
["b_list"]=>
array(1) {
["3B3"]=>
array(3) {
["b_id"]=>
string(1) "3"
["b_name"]=>
string(2) "B3"
["c_list"]=>
array(1) {
["4C4"]=>
array(3) {
["c_id"]=>
string(1) "4"
["c_name"]=>
string(2) "C4"
["d_list"]=>
&NULL
}
}
}
}
}
}
This is rather interesting. As far as I can tell, you are trying to transform a flat array into a multidimensional array, as well as transforming the keys into a multidimensional representation.
The top level difference seems to reside in the part before the underscore of the a_* keys.
Then, for each of these keys, every other *_ letters should induce it's own list.
This recursive function does the trick without hardcoding, will work with whatever number of levels, letters (or whatever else) and right identifiers.
It seems to return exactly the json you show in the sample ($array being the array as defined in your question)
$multidimension = multidimensionalify($array, ['a', 'b', 'c'], ['name']);
var_dump(json_encode($multidimension, JSON_PRETTY_PRINT));
function multidimensionalify(
array $input,
array $topLevelLetters,
array $rightHandIdentifiers,
$level = 0,
$parentId = null,
$uniqueString = 'id'
)
{
$thisDimension = [];
$thisLetter = $topLevelLetters[$level];
foreach ($input as $entry)
{
$thisId = $entry["{$thisLetter}_{$uniqueString}"];
$condition = true;
if ($parentId !== null)
{
$parentLetter = $topLevelLetters[$level - 1];
$condition = $entry["{$parentLetter}_{$uniqueString}"] === $parentId;
}
if (!isset($thisDimension[$thisId]) && $condition)
{
$thisObject = new stdClass;
$thisObject->{"{$thisLetter}_{$uniqueString}"} = $thisId;
foreach ($rightHandIdentifiers as $identifier)
{
$thisObject->{"{$thisLetter}_{$identifier}"} = $entry["{$thisLetter}_{$identifier}"];
}
if (isset($topLevelLetters[$level + 1])) {
$nextLetter = $topLevelLetters[$level + 1];
$thisObject->{"{$nextLetter}_list"} = multidimensionalify($input, $topLevelLetters, $rightHandIdentifiers, $level + 1, $thisId, $uniqueString);
}
$thisDimension[$thisId] = $thisObject;
}
}
return array_values($thisDimension);
}
Try this function just pass your array and key name for grouping and then convert to json.
public function _group_by($array, $key) {
$return = array();
foreach ($array as $val) {
$return[$val[$key]][] = $val;
}
return $return;
}
This question already has answers here:
Is there a function to extract a 'column' from an array in PHP?
(15 answers)
Closed last month.
I have an array which is multidimensional for no reason
/* This is how my array is currently */
Array
(
[0] => Array
(
[0] => Array
(
[plan] => basic
)
[1] => Array
(
[plan] => small
)
[2] => Array
(
[plan] => novice
)
[3] => Array
(
[plan] => professional
)
[4] => Array
(
[plan] => master
)
[5] => Array
(
[plan] => promo
)
[6] => Array
(
[plan] => newplan
)
)
)
I want to convert this array into this form
/*Now, I want to simply it down to this*/
Array (
[0] => basic
[1] => small
[2] => novice
[3] => professional
[4] => master
[5] => promo
[6] => newplan
)
Any idea how to do this?
This single line would do that:
$array = array_column($array, 'plan');
The first argument is an array | The second argument is an array key.
For details, go to official documentation: https://www.php.net/manual/en/function.array-column.php.
Assuming this array may or may not be redundantly nested and you're unsure of how deep it goes, this should flatten it for you:
function array_flatten($array) {
if (!is_array($array)) {
return FALSE;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
}
else {
$result[$key] = $value;
}
}
return $result;
}
If you come across a multidimensional array that is pure data, like this one below, then you can use a single call to array_merge() to do the job via reflection:
$arrayMult = [ ['a','b'] , ['c', 'd'] ];
$arraySingle = call_user_func_array('array_merge', $arrayMult);
// $arraySingle is now = ['a','b', 'c', 'd'];
Just assign it to it's own first element:
$array = $array[0];
For this particular case, this'll do:
$array = array_map('current', $array[0]);
It's basically the exact same question is this one, look at some answers there: PHP array merge from unknown number of parameters.
$singleArray = array();
foreach ($multiDimensionalArray as $key => $value){
$singleArray[$key] = $value['plan'];
}
this is best way to create a array from multiDimensionalArray array.
thanks
Problem array:
array:2 [▼
0 => array:3 [▼
0 => array:4 [▼
"id" => 8
"name" => "Veggie Burger"
"image" => ""
"Category_type" => "product"
]
1 => array:4 [▼
"id" => 9
"name" => "Veggie Pitta"
"image" => ""
"Category_type" => "product"
]
2 => array:4 [▼
"id" => 10
"name" => "Veggie Wrap"
"image" => ""
"Category_type" => "product"
]
]
1 => array:2 [▼
0 => array:4 [▼
"id" => 18
"name" => "Cans 330ml"
"image" => ""
"Category_type" => "product"
]
1 => array:4 [▼
"id" => 19
"name" => "Bottles 1.5 Ltr"
"image" => ""
"Category_type" => "product"
]
]
]
Solution array:
array:5 [▼
0 => array:4 [▼
"id" => 8
"name" => "Veggie Burger"
"image" => ""
"Category_type" => "product"
]
1 => array:4 [▼
"id" => 9
"name" => "Veggie Pitta"
"image" => ""
"Category_type" => "product"
]
2 => array:4 [▼
"id" => 10
"name" => "Veggie Wrap"
"image" => ""
"Category_type" => "product"
]
3 => array:4 [▼
"id" => 18
"name" => "Cans 330ml"
"image" => ""
"Category_type" => "product"
]
4 => array:4 [▼
"id" => 19
"name" => "Bottles 1.5 Ltr"
"image" => ""
"Category_type" => "product"
]
]
Write this code and get your solution , $subcate is your multi dimensional array.
$singleArrayForCategory = array_reduce($subcate, 'array_merge', array());
none of answers helped me, in case when I had several levels of nested arrays. the solution is almost same as #AlienWebguy already did, but with tiny difference.
function nestedToSingle(array $array)
{
$singleDimArray = [];
foreach ($array as $item) {
if (is_array($item)) {
$singleDimArray = array_merge($singleDimArray, nestedToSingle($item));
} else {
$singleDimArray[] = $item;
}
}
return $singleDimArray;
}
test example
$array = [
'first',
'second',
[
'third',
'fourth',
],
'fifth',
[
'sixth',
[
'seventh',
'eighth',
[
'ninth',
[
[
'tenth'
]
]
],
'eleventh'
]
],
'twelfth'
];
$array = nestedToSingle($array);
print_r($array);
//output
array:12 [
0 => "first"
1 => "second"
2 => "third"
3 => "fourth"
4 => "fifth"
5 => "sixth"
6 => "seventh"
7 => "eighth"
8 => "ninth"
9 => "tenth"
10 => "eleventh"
11 => "twelfth"
]
You can do it just using a loop.
$singleArray = array();
foreach ($multiDimensionalArray as $key => $value){
$singleArray[$key] = $value['plan'];
}
Your sample array has 3 levels. Because the first level has only [0], you can hardcode your access into it and avoid an extra function/construct call.
(Code Demos)
array_walk_recursive() is handy and versatile, but for this task may be overkill and certainly a bit more convoluted in terms of readability.
array_walk_recursive($array, function($leafvalue)use(&$flat){$flat[] = $leafvalue;});
var_export($flat);
If this was my code, I'd be using array_column() because it is direct and speaks literally about the action being performed.
var_export(array_column($array[0], 'plan'));
Of course a couple of `foreach() loops will perform very efficiently because language constructs generally perform more efficiently than function calls.
foreach ($array[0] as $plans) {
foreach ($plans as $value) {
$flat[] = $value;
}
}
var_export($flat);
Finally, as a funky alternative (which I can't imagine actually putting to use unless I was writing code for someone whom I didn't care for) I'll offer an array_merge_recursive() call with a splat operator (...).
var_export(array_merge_recursive(...$array[0])['plan']);
Despite that array_column will work nice here, in case you need to flatten any array no matter of it's internal structure you can use this array library to achieve it without ease:
$flattened = Arr::flatten($array);
which will produce exactly the array you want.
This simple code you can use
$array = array_column($array, 'value', 'key');
Recently I've been using AlienWebguy's array_flatten function but it gave me a problem that was very hard to find the cause of.
array_merge causes problems, and this isn't the first time that I've made problems with it either. If you have the same array keys in one inner array that you do in another, then the later values will overwrite the previous ones in the merged array.
Here's a different version of array_flatten without using array_merge:
function array_flatten($array) {
if (!is_array($array)) {
return FALSE;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$arrayList=array_flatten($value);
foreach ($arrayList as $listItem) {
$result[] = $listItem;
}
}
else {
$result[$key] = $value;
}
}
return $result;
}
There is an error in most voted answer. Here is the correct version.
function array_flatten($array) {
if (!is_array($array)) {
return FALSE;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, array_flatten($value));
}
else {
$result[] = $value;
}
}
return $result;
}
The difference is on the line $result[] = $value;
Original answer was $result[$key] = $value;
The $key index is incorrect after flattering any array in the cycle.
Following this pattern
$input = array(10, 20, array(30, 40), array('key1' => '50', 'key2'=>array(60), 70));
Call the function :
echo "<pre>";print_r(flatten_array($input, $output=null));
Function Declaration :
function flatten_array($input, $output=null) {
if($input == null) return null;
if($output == null) $output = array();
foreach($input as $value) {
if(is_array($value)) {
$output = flatten_array($value, $output);
} else {
array_push($output, $value);
}
}
return $output;
}
I've written a complement to the accepted answer. In case someone, like myself need a prefixed version of the keys, this can be helpful.
Array
(
[root] => Array
(
[url] => http://localhost/misc/markia
)
)
Array
(
[root.url] => http://localhost/misc/markia
)
<?php
function flattenOptions($array, $old = '') {
if (!is_array($array)) {
return FALSE;
}
$result = array();
foreach ($array as $key => $value) {
if (is_array($value)) {
$result = array_merge($result, flattenOptions($value, $key));
}
else {
$result[$old . '.' . $key] = $value;
}
}
return $result;
}
I had come across the same requirement to flatter multidimensional array into single dimensional array than search value using text in key. here is my code
$data = '{
"json_data": [{
"downtime": true,
"pfix": {
"max": 100,
"threshold": 880
},
"ints": {
"int": [{
"rle": "pri",
"device": "laptop",
"int": "Ether3",
"ip": "127.0.0.3"
}],
"eth": {
"lan": 57
}
}
},
{
"downtime": false,
"lsi": "987654",
"pfix": {
"min": 10000,
"threshold": 890
},
"mana": {
"mode": "NONE"
},
"ints": {
"int": [{
"rle": "sre",
"device": "desk",
"int": "Ten",
"ip": "1.1.1.1",
"UF": true
}],
"ethernet": {
"lan": 2
}
}
}
]
}
';
$data = json_decode($data,true);
$stack = &$data;
$separator = '.';
$toc = array();
while ($stack) {
list($key, $value) = each($stack);
unset($stack[$key]);
if (is_array($value)) {
$build = array($key => ''); # numbering without a title.
foreach ($value as $subKey => $node)
$build[$key . $separator . $subKey] = $node;
$stack = $build + $stack;
continue;
}
if(!is_numeric($key)){
$toc[$key] = $value;
}
}
echo '<pre/>';
print_r($toc);
My output:
Array
(
[json_data] =>
[json_data.0] =>
[json_data.0.downtime] => 1
[json_data.0.pfix] =>
[json_data.0.pfix.max] => 100
[json_data.0.pfix.threshold] => 880
[json_data.0.ints] =>
[json_data.0.ints.int] =>
[json_data.0.ints.int.0] =>
[json_data.0.ints.int.0.rle] => pri
[json_data.0.ints.int.0.device] => laptop
[json_data.0.ints.int.0.int] => Ether3
[json_data.0.ints.int.0.ip] => 127.0.0.3
[json_data.0.ints.eth] =>
[json_data.0.ints.eth.lan] => 57
[json_data.1] =>
[json_data.1.downtime] =>
[json_data.1.lsi] => 987654
[json_data.1.pfix] =>
[json_data.1.pfix.min] => 10000
[json_data.1.pfix.threshold] => 890
[json_data.1.mana] =>
[json_data.1.mana.mode] => NONE
[json_data.1.ints] =>
[json_data.1.ints.int] =>
[json_data.1.ints.int.0] =>
[json_data.1.ints.int.0.rle] => sre
[json_data.1.ints.int.0.device] => desk
[json_data.1.ints.int.0.int] => Ten
[json_data.1.ints.int.0.ip] => 1.1.1.1
[json_data.1.ints.int.0.UF] => 1
[json_data.1.ints.ethernet] =>
[json_data.1.ints.ethernet.lan] => 2
)
This is my contribuition
function arrayUnica($array, $prefix = "")
{
if (!is_array($array)) {
return false;
}
$new_array = [];
foreach ($array as $key => $value) {
if (is_array($value)) {
$key = is_int($key) ? $prefix . $key . "-" : $key . "_";
$new_array = array_merge($new_array, arrayUnica($value, $key));
} else {
$new_array[$prefix . $key] = $value;
}
}
return $new_array;
}
Hope this will helpful for you,
$array= 'YOUR_MULTIDIMENSIONAL_ARRAY';
$arr=[];
array_walk_recursive($array, function($k){global $arr; $arr[]=$k;});
print_r($arr);
I have done this with OOP style
$res=[1=>[2,3,7,8,19],3=>[4,12],2=>[5,9],5=>6,7=>[10,13],10=>[11,18],8=>[14,20],12=>15,6=>[16,17]];
class MultiToSingle{
public $result=[];
public function __construct($array){
if(!is_array($array)){
echo "Give a array";
}
foreach($array as $key => $value){
if(is_array($value)){
for($i=0;$i<count($value);$i++){
$this->result[]=$value[$i];
}
}else{
$this->result[]=$value;
}
}
}
}
$obj= new MultiToSingle($res);
$array=$obj->result;
print_r($array);
Multi dimensional array to single array with one line code !!!
Enjoy the code.
$array=[1=>[2,5=>[4,2],[7,8=>[3,6]],5],4];
$arr=[];
array_walk_recursive($array, function($k){global $arr; $arr[]=$k;});
print_r($arr);
...Enjoy the code.
Try this it works for me:
$newArray = array();
foreach($operator_call_logs as $array) {
foreach($array as $k=>$v) {
$newArray[$k] = $v;
}
}
Save this as a php file, simply import and use single_array() function
<?php
$GLOBALS['single_array']=[];
function array_conveter($array_list){
if(is_array($array_list)){
foreach($array_list as $array_ele){
if(is_array($array_ele)){
array_conveter($array_ele);
}else{
array_push($GLOBALS['single_array'],$array_ele);
}
}
}else{
array_push($GLOBALS['single_array'],$array_list);
}
}
function single_array($mix){
foreach($mix as $single){
array_conveter($single);
}return $GLOBALS['single_array'];
$GLOBALS['single_array']=[];
}
/* Example convert your multi array to single */
$mix_array=[3,4,5,[4,6,6,7],'abc'];
print_r(single_array($mix_array));
?>
if use php version 7.4 and above
$users = [
[
'Ahmed',
'Mohammed',
],
[
'Saeed',
'Rami',
'Haider',
],
];
$admin = array_merge(...$users);
I'm fairly sure I'm missing something blindingly obvious here but here it goes.
I am working on updating a search function in an application which was running a loop and doing a very large number of sql queries to get object / table relations to one large query that returns everything. However the only way I could think to return relations was period separated, what I am now wanting to do is take the flat array of keys and values and convert it into an associative array to then be jsonified with json_encode.
For example what I have is this...
array(
"ID"=>10,
"CompanyName"=>"Some Company",
"CompanyStatusID"=>2,
"CompanyStatus.Status"=>"Active",
"addressID"=>134,
"address.postcode"=>"XXX XXXX",
"address.street"=>"Some Street"
);
And what I want to turn it into is this...
array(
"ID"=>10,
"CompanyName"=>"Some Company",
"CompanyStatusID"=>2,
"CompanyStatus"=>array(
"Status"=>"Active"
),
"addressID"=>134,
"address"=>array(
"postcode"=>"XXX XXXX",
"street"=>"Some Street"
)
);
Now I'm sure this should be a fairly simple recursive loop but for the life of me this morning I can't figure it out.
Any help is greatly appreciated.
Regards
Graham.
Your function was part way there mike, though it had the problem that the top level value kept getting reset on each pass of the array so only the last period separated property made it in.
Please see updated version.
function parse_array($src) {
$dst = array();
foreach($src as $key => $val) {
$parts = explode(".", $key);
if(count($parts) > 1) {
$index = &$dst;
$i = 0;
$count = count($parts)-1;
foreach(array_slice($parts,0) as $part) {
if($i == $count) {
$index[$part] = $val;
} else {
if(!isset($index[$part])){
$index[$part] = array();
}
}
$index = &$index[$part];
$i++;
}
} else {
$dst[$parts[0]] = $val;
}
}
return $dst;
}
I am sure there is something more elegant, but quick and dirty:
$arr = array(
"ID"=>10,
"CompanyName"=>"Some Company",
"CompanyStatusID"=>2,
"CompanyStatus.Status"=>"Active",
"addressID"=>134,
"address.postcode"=>"XXX XXXX",
"address.street"=>"Some Street"
);
$narr = array();
foreach($arr as $key=>$val)
{
if (preg_match("~\.~", $key))
{
$parts = split("\.", $key);
$narr [$parts[0]][$parts[1]] = $val;
}
else $narr [$key] = $val;
}
$arr = array(
"ID" => 10,
"CompanyName" => "Some Company",
"CompanyStatusID" => 2,
"CompanyStatus.Status" => "Active",
"addressID" => 134,
"address.postcode" => "XXX XXXX",
"address.street" => "Some Street",
"1.2.3.4.5" => "Some nested value"
);
function parse_array ($src) {
$dst = array();
foreach($src as $key => $val) {
$parts = explode(".", $key);
$dst[$parts[0]] = $val;
if(count($parts) > 1) {
$index = &$dst[$parts[0]];
foreach(array_slice($parts, 1) as $part) {
$index = array($part => $val);
$index = &$index[$part];
}
}
}
return $dst;
}
print_r(parse_array($arr));
Outputs:
Array
(
[ID] => 10
[CompanyName] => Some Company
[CompanyStatusID] => 2
[CompanyStatus] => Array
(
[Status] => Active
)
[addressID] => 134
[address] => Array
(
[street] => Some Street
)
[1] => Array
(
[2] => Array
(
[3] => Array
(
[4] => Array
(
[5] => Some nested value
)
)
)
)
)