Split array in arrays for all its columns [duplicate] - php

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 8 months ago.
I'm using the array_column function to convert a 3d array into new arrays with the values.
I have multiple columns that all need to be converted in an array. Is there an easier or cleaner way to do this?
Instead of doing this:
$levels = array_column($arr, 'level');
$times = array_column($arr, 'time');
$numbers = array_column($arr, 'number');
Here's an example of my array:
$arr = [
[
'level' => 0,
'time' => 3,
'number' => 5
],
[
'level' => 1,
'time' => 4,
'number' => 3
],
];

I think the simplest way to do this is with a nested loop.
foreach($arr as $inner) {
foreach($inner as $key => $value) {
$columns[$key][] = $value;
}
}
This will produce a result like this:
[
'level' => [0, 1],
'time' => [3, 4],
'number' => [5, 3]
]
If you really want to create separate variables like the example in your question, you can use variable variables for that. I would advise against it, but here's an example of that.
foreach($arr as $inner) {
foreach($inner as $key => $value) {
$$key[] = $value;
}
}
Dynamically creating variables like that is risky. You can inadvertently overwrite other variables if one of the column names happens to be the same. Using the first method will contain the result in one predictable place, and $columns['level'] can be used in the following code just the same as a separate $level variable would.

Related

Transpose data in an associative array of indexed arrays [duplicate]

This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 6 months ago.
I'm not sure how to search for the problem I'm facing, so that's why I'm asking here.
I want to know if there is a native php-function to transform following array I get from a html-form:
Original Array
$array = [
'product_template_id' => [
'0' => '1',
'1' => '2'
],
'amount' => [
'0' => '50',
'1' => '100'
]
]
Desired Array
$array = [
'0' => [
'product_template_id' => '1',
'amount' => '50'
],
'1' => [
'product_template_id' => '2',
'amount' => '100'
]
]
I know this can be done with a loop, but that's not what I'm asking for.
PS(not my main question, just a sidequestion): How can I bulk format code in stackoverflow? Is it always 4 spaces? How can I perform the formatting quicker?
edit: PS is not the main question, it is more of a sidenote which has already been answered by #RiggsFolly
Just as prove of concept you can use array_map:
$keys = array_keys($array);
// For < PHPv5.6
// $zip = call_user_func_array('array_map', array_merge([null], $array));
$zip = array_map(null, ...array_values($array));
$result = array_map(function ($item) use ($keys) {
return array_combine($keys, $item);
}, $zip);
Here is working demo.
But in practice, there is too much overhead for so simple problem.
EDIT:
Here I am zipping (getting one corresponding element from each array and creating an array of this elements) all child arrays. It is done with array_map using its property:
An interesting use of this function is to construct an array of arrays, which can be easily performed by using NULL as the name of the callback function
As array_map can take an arbitrary number of arrays, I supply them to it with '...' splat operator.
This does what you need!
for ($x = 0; $x < count($array['amount']); $x ++) {
$arr[$x] = [
'product_template_id' => $array['product_template_id'][$x],
'amount' => $array['amount'][$x],
];
}
See here for a working example https://3v4l.org/dokHK

PHP having multiple "child" arrays within "parent" array and how to access them

i am trying to create an array which stores various photo albums,
so far i have the following code
$photos = array(
array("karate","1","2"),
array("judo","1","2"),
array("kickboxing","1","2"),
array("womenselfdefense","1","2")
);
$sections = array("karate","judo","kickboxing","womenselfdefense");
foreach($sections as $keys => $section)
{
echo count($photos[$section]);
}
but i dont think i have set up my arrays properly, ideally i'd like the main array $photos to have 4 separate arrays $karate,$judo,$kickboxing,$womenselfdefense within it.
i want to start of by counting the number of items in each array and then choose a random item within each array, however i believe at the moment i have 4 unnamed arrays within the photos array and therefor my code returns several Undefined index: errors
can anyone help me with this please
You could use the name of the photo album as the key for the photos array.
$photos = array(
"karate" => array("1","2"),
"judo" => array("1","2"),
"kickboxing" => array("1","2"),
"womenselfdefense" => array("1","2")
);
$sections = array("karate","judo","kickboxing","womenselfdefense");
foreach($sections as $keys => $section)
{
echo count($photos[$section]).'<br>';
}
I think you're looking for an associative array, which uses a label instead of a number as a key:
$photos = array(
"karate" => array("1","2"),
"judo" => array("1","2"),
"kickboxing" => array("1","2"),
"womenselfdefense" => array("1","2")
);
foreach ($photos as $section=>$values) {
//now $values is your array of numbers
echo count($values);
}
Or, in modern syntax:
$photos = [
"karate" => [1, 2],
"judo" => [1, 2],
"kickboxing" => [1, 2],
"womenselfdefense" => [1, 2],
];
You are trying to access the arrays without assigning the higher level arrays any keys.
Try something like this:
$photos = array(
'karate' => array("karate","1","2"),
'judo' => array("judo","1","2"),
'kickboxing' => array("kickboxing","1","2"),
'womenselfdefense' => array("womenselfdefense","1","2")
);
I think you mean to use
echo count($photos[$keys]);

Split multidimensional array into arrays

So I have a result from a form post that looks like this:
$data = [
'id_1' => [
'0' => 1,
'1' => 2
],
'id_2' => [
'0' => 3,
'1' => 4
],
'id_3' => [
'0' => 5,
'1' => 6
]
];
What I want to achieve is to split this array into two different arrays like this:
$item_1 = [
'id_1' => 1,
'id_2' => 3,
'id_3' => 5
]
$item_2 = [
'id_1' => 2,
'id_2' => 4,
'id_3' => 6
]
I've tried using all of the proper array methods such as array_chunk, array_merge with loops but I can't seem to get my mind wrapped around how to achieve this. I've seen a lot of similar posts where the first keys doesn't have names like my array does (id_1, id_2, id_3). But in my case the names of the keys are crucial since they need to be set as the names of the keys in the individual arrays.
Much shorter than this will be hard to find:
$item1 = array_map('reset', $data);
$item2 = array_map('end', $data);
Explanation
array_map expects a callback function as its first argument. In the first line this is reset, so reset will be called on every element of $data, effectively taking the first element values of the sub arrays. array_map combines these results in a new array, keeping the original keys.
The second line does the same, but with the function end, which effectively grabs the last element's values of the sub-arrays.
The fact that both reset and end move the internal array pointer, is of no concern. The only thing that matters here is that they also return the value of the element where they put that pointer to.
Solution without loop and just for fun:
$result = [[], []];
$keys = array_keys($data);
array_map(function($item) use(&$result, &$keys) {
$key = array_shift($keys);
$result[0][$key] = $item[0];
$result[1][$key] = $item[1];
}, $data);
Just a normal foreach loop will do.
$item_1 = [];
$item_2 = [];
foreach ($data as $k => $v){
$item_1[$k] = $v[0];
$item_2[$k] = $v[1];
}
Hope this helps.

Search for key and value in php arrays

So I have two array, the first one is like:
$MyArray = [
['id' => 1, number => 32],
['id' => 2, number => 4]
];
and the other is like:
$OtherArray = [
['id' => 1, 'show' => X],
['id' => 5, 'show' => X]
];
Where is X, I want it to be equal with the 'number' value of $MyArray where key 'id' = its id.
If there is no $MyArray.id which is equal to $OtherArray.id then it should return 0.
I hope you understand what I mean. I tried everything, what I could, yet, with no success.
Have you tried using a foreach loop here?
Here is a quick example... PHPaste Snippet
<?php
$firstArray = array(
array(
"id" => 1,
"something" => "Hello, World!"
),
array(
"id" => 3, // 3 on purpose
"something" => "Hello, mom?"
)
);
$secondArray = array(
array(
"id" => 1,
"thing" => null
),
array(
"id" => 2,
"thing" => null
)
);
foreach ($firstArray as $key => $value) {
foreach ($secondArray as $k => $v) {
if ($value['id'] == $v['id']) {
echo "Found one!\n------\n" . print_r($value, true) . "\ncontains the same ID as\n\n" . print_r($v, true) . "\n------\n";
// you may also do this if you want
// $secondArray[$k]['thing'] = $value['id'];
// this would set "thing" (in the second array) to the value of "id" (in the first array)
}
}
}
EDIT Here is a second example, displaying how you could use it as a function... PHPaste Snippet.
Note: I used the OLD array syntax because it's easier for new programmers to understand.
So, essentially what you are doing is iterating through each item in $firstArray, comparing it to each item in $secondArray, by doing a nested foreach within side the first foreach if that makes sense...?
Here is what I just said in simple form:
go through each item in array 1
--> compare it to each item in array 2
You may also notice my use of PHP's lovely function, print_r(). This displays objects and arrays in a slightly, clearer, form.
You can also see that I am getting the values from within the arrays by using $value['id'] and $v['id']. These were defined in my foreach declaration, foreach ($firstArray as $key => $value); $value is an associative array, so you can simply get a value by key just as you would if you created an array like this:
$myArray = [
"id" => 1
];
and grabbed values like this:
echo $myArray['id']; // 1
Hopefully this helped.

Merge row data from multiple arrays

I have two arrays as shown below. I need to merge the content of the arrays so that I can get the structure as shown in the third array at last. I have checked array_merge but can't figure out the way this is possible. Any help appreciated. Thanks.
[
['gross_value' => '100', 'quantity' => '1'],
['gross_value' => '200', 'quantity' => '1']
]
and
[
['item_title_id' => '1', 'order_id' => '4'],
['item_title_id' => '2', 'order_id' => '4']
];
I should get a merged array like this:
[
[
'gross_value' => '100',
'quantity' => '1',
'item_title_id' => '1',
'order_id' => 4
],
[
'gross_value' => '200',
'quantity' => '1',
'item_title_id' => '2',
'order_id' => 4
]
]
Use array_merge_recursive :
Convert all numeric key to strings, (make is associative array)
$result = array_merge_recursive($ar1, $ar2);
print_r($result);
See live demo here
how about:
$arr1 = array(
0 => array(
'gross_value' => '100',
'quantity' => '1'
),
1 => array(
'gross_value' => '200',
'quantity' => '1'
)
);
$arr2 = array(
0 => array(
'item_title_id' => '1',
'order_id' => '4'
),
1 => array(
'item_title_id' => '2',
'order_id' => '4'
)
);
$arr = array();
foreach($arr1 as $k => $v) {
array_push($arr, array_merge($v, $arr2[$k]));
}
print_r($arr);
output:
Array
(
[0] => Array
(
[gross_value] => 100
[quantity] => 1
[item_title_id] => 1
[order_id] => 4
)
[1] => Array
(
[gross_value] => 200
[quantity] => 1
[item_title_id] => 2
[order_id] => 4
)
)
Have a look at array_merge
I would probably iterate over the arrays and merge them manually.
$result = array();
foreach ( $array1 as $key => $item )
{
$result[$key] = array_merge($array1[$key], $array2[$key]);
}
You will have an issue if the top-level arrays don't have strictly matching keys though.
If you have $array1 and $array2, try this:
foreach($array1 as $key1=>$innerArray){
$array1[$key1]['item_title_id'] = $array2[$key1]['item_title_id'];
$array1[$key1]['order_id'] = $array2[$key1]['order_id'];
}
The problem with things like merge recursive is that they don't know when to stop.
In some scenarios you want to stop traversing down an array and simply take a given value if it exists.
For instance if you have to override a nested config array you might not want the default keys to stick around at a a specific level.
here is my solution:
public static function merge_lvl2(){
$args = func_get_args();
return static::merge($args, 2);
}
public static function merge($args, $maxDepth = null, $depth = 1)
{
$merge = [];
foreach($args as $arg) {
if (is_array($arg)) {
if (is_array($merge)) {
if ($maxDepth == $depth) {
$arg += $merge;
$merge = $arg;
} else {
$merge = array_merge($merge, $arg);
}
} else {
$merge = $arg;
}
}
}
if ($maxDepth !== $depth) {
foreach($args as $a) {
if (is_array($a)) {
foreach($a as $k => $v) {
if (isset($merge[$k]) && is_array($merge[$k])) {
$merge[$k] = static::merge([$merge[$k], $v], $maxDepth, $depth + 1);
}
}
}
}
}
return $merge;
}
You can pass as many arrays to merge as you want to.
$merged = ClassName::merge_lvl2([..array1..], [..array2..], [..array3..], etc...);
It will stop merging at level 2 and accept the last instance of the key as an override instead of a merge.
You can also call merge directly with an array of args and setting the max depth.
If no max depth is set it will traverse the entire array.
The most modern, elegant, concise way to merge rows from two or more arrays (or the rows from a multidimensional array with 3 or more levels of depth) is to call array_merge() on each row (array_replace() can also be used). array_map() can call array_merge by its string name and the input data can be split into individual arguments with the "spread operator" (...) when needed.
Code for the OP's arrays: (Demo)
var_export(
array_map('array_merge', $arr1, $arr2)
);
The above technique will return a newly indexed array (though you might not notice because the sample input arrays were indexed to begin with). If your input data has associative first-level keys, they will be ignored and destroyed by this technique. If you have non-numeric first-level keys and want to merge on those, then array_merge_recursive() is likely to be the ideal native function - Demo.
However, it must be said, that for the OP's sample data array_merge_recursive() IS NOT a correct technique.
My first snippet is conveniently extended if you have more than two arrays which need their rows to be merge based on their positions. (Demo)
var_export(
array_map('array_merge', $arr1, $arr2, $arr3)
);
And as mentioned earlier, the spread operator can be used to unpack deeper arrays with the same result. Again, the number of subarrays containing rows can be dynamic. If your deep array only has one subarray containing rows, then the result will be a "flattening" effect where the top level is removed.
Code with new data structure: (Demo)
$masterArray = [
[
['gross_value' => '100', 'quantity' => '5'],
['gross_value' => '200', 'quantity' => '6']
],
[
['item_title_id' => '1', 'order_id' => '3'],
['item_title_id' => '2', 'order_id' => '4']
],
[
['foo' => 'bar1'],
['foo' => 'bar2']
]
];
var_export(
array_map('array_merge', ...$masterArray)
);
To be fair, array_replace_recursive() does provide the desired result using the OP's sample data, but I find the technique to be semantically misleading. (Demo)
All that said, you are not forced to use PHP's native array functions; you can use classic loops as well -- you will have several ways to "unite" the rows inside the loop. This approach is a little less D.R.Y. because you need to explicitly specific the separate arrays that you wish to synchronously iterate. Just make sure that you understand the nuanced differences in using array_merge(), array_replace(), and the union operator (+) with different qualities of data. Hint: associative, non-numeric keyed data in the respective rows will be affected when key collisions occur. Be careful to use a merging technique that will not overwrite the wrong data when rows share associative keys.
array_merge() to build a new array: (array_merge() Demo) (array_replace() Demo) (array union operator + Demo)
$result = [];
foreach ($arr1 as $i => $row) {
$result[] = array_merge($row, $arr2[$i]);
}
var_export($result);
Alternative, you can use the same general approach, but instead of populating a new $result array, you can merge data into the first array.
(array_merge() Demo) (array_replace() Demo) (array union assignment operator += Demo)
foreach ($arr1 as $i => &$row) {
$row = array_merge($row, $arr2[$i]);
}
var_export($arr1);
For the sake of completeness, if you have an indexed array of indexed arrays, then you might even use iterated calls of array_push() with the spread operator to achieve a similar functionality. This quite literally, indicatively appends the row data from subsequent arrays to the first array's rows.
Code: (Demo)
$arr1 = [
['A', 'B', 'C'],
['F', 'G']
];
$arr2 = [
['D', 'E'],
['H', 'I', 'J', 'L']
];
foreach ($arr1 as $i => &$row) {
array_push($row, ...$arr2[$i]);
}
var_export($arr1);
Related non-duplicate content on Stack Overflow:
Partially merge one array's row data with another another array:Add column of values from one array to another
Merge two flat arrays to create an array of merged rows:Transforming array values in elements of a subarray using PHP
Merge rows with indexed elements, remove duplicates and reindex:Merge two multidimensional arrays, preserve numeric keys, and combine values inside array
Merge arrays containing objects:Merge rows of two arrays containing objects by first level index
Push single elements from one array to rows in another array:Push elements from one array into rows of another array (one element per row)
On the above pages, the rabbit hole goes further because I've linked other related pages to them. Keep researching until you find what you need.
If you are using Laravel, you might be interested in its combine() and collect() methods.

Categories