This question already has answers here:
Transposing multidimensional arrays in PHP
(12 answers)
Closed 2 years ago.
For example if a matrix is:
1 2
3 4
5 6
Then transpose of above matrix will be:
1 3 5
2 4 6
This is my current code:
<?php
// transpose matrix
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
foreach ($trans as $key => $val){
foreach ($trans[$key] as $k => $v){
echo $v;
}
}
?>
There's a quirky PHP way to transpose a 2d array:
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
array_unshift($trans, null);
$trans = call_user_func_array('array_map', $trans);
var_dump($trans);
Demo
EDIT Easier approach using PHP 5.6 array unpacking
With the introduction of the array argument unpacking feature in PHP 5.6, we can simplify this still further:
$trans = array(
array(1, 2),
array(3, 4),
array(5, 6)
);
$trans = array_map(null, ...$trans);
var_dump($trans);
EDIT Explanation
Quoting from the PHP docs for the array_map() function:
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
(See Example #4 from that docs page for an example of what this does)
The array_unshift($trans, null) that we perform first is providing that NULL callback, and we use call_user_func_array() because we don't necessarily know how many values there are in our $trans array. What we're doing using that call_user_func_array() is the equivalent of:
$trans = array_map(NULL, $trans[0], $trans[1], $trans[2]);
for your example array, because the top-level of your 2-d array has three elements (keys 0, 1 and 2).
Effectively, this NULL callback loops through all the arrays in parallel taking each value from them in turn to build a new array:
$maxArraySize = max(count($array[0], $array[1], $array[2]);
// $maxArraySize will have a value of 2 in your case,
// because your sub-arrays are all equal size
$newArray = [];
for($i = 0; $i < $maxArraySize; ++$i) {
$tmpArray = [];
$tmpArray[] = $array[0][$i];
$tmpArray[] = $array[1][$i];
$tmpArray[] = $array[2][$i];
$newArray[] = $tmpArray[];
}
There's a couple of extra checks in there
it doesn't care if your arrays are associative or enumerated in either dimension, because it accesses the $ith element, not the index
If the sub-arrays aren't all the same length, then it effectively pads the shorter sub-arrays with null values to match the length of the longest
It doesn't matter how many arrays you pass in, it will work with them all in parallel
I believe this works with rectangular arrays as well.
The trick: return array_map(null, ...$squareArray); seems to work in an unexpected way for a single column array
function RotateSquare2DArray($squareArray)
{
if ($squareArray == null) { return null; }
$rotatedArray = array();
$r = 0;
foreach($squareArray as $row) {
$c = 0;
if (is_array($row)) {
foreach($row as $cell) {
$rotatedArray[$c][$r] = $cell;
++$c;
}
}
else $rotatedArray[$c][$r] = $row;
++$r;
}
return $rotatedArray;
}
If the array is associative, I use this
function RotateSquareAssociativeArray($squareArray)
{
if ($squareArray == null) { return null; }
$rotatedArray = array();
$r = 0;
foreach($squareArray as $c=>$row) {
if (is_array($row)) {
foreach($row as $key=>$cell) {
$rotatedArray[$key][$c] = $cell;
}
}
else {
$rotatedArray[$c][$r] = $row;
}
++$r;
}
return $rotatedArray;
}
Related
I've been banging my head against this problem for a while. I feel like it should be simple, but I'm having a hard time coming up with a solution.
I'm looking to pre-populate a database, and I need to create SQL statements with some foreign key values. It would be tedious to hand-code them, so naturally I decided to do it in code.
What I want are series of arrays that have values as such:
[1]
[2]
[3]
[1,1]
[1,2]
[1,3]
[2,1]
[2,2]
...
[1,1,1]
[1,1,2]
[1,1,3]
...
[3,1,1]
...
[3,3,3]
I want to specify the number of values in the array, and the numerical value at which it causes the preceeding value to roll over.
In the example I gave above, it would be like generate(3,3), since the maximum number of elements is 3, and the highest value is 3.
How could I write some code that would give me this series of arrays?
This is a recursive function that will generate each of the combinations of the ranges up to the maximum value, with elements in each array from 1 to the number specified:
function generate($elements, $maxvalue) {
if ($elements == 0) return array();
$result = array();
foreach (range(1, $maxvalue) as $el) {
$result[] = array($el);
}
foreach (range(1, $maxvalue) as $el) {
foreach (generate($elements - 1, $maxvalue) as $arr) {
$result[] = array($el, ...$arr);
}
}
return $result;
}
$combs = generate(3, 3);
Output is too long to show here but can be seen in this demo on 3v4l.org
Note for PHP < 7.4, replace
$result[] = array($el, ...$arr);
with
$result[] = array_merge(array($el), $arr);
Here's a version using generators (which may be slightly easier on memory than pure arrays):
function generate(int $elementsCount, int $maxValue, array $current = []): \Generator
{
for ($value = 1; $value <= $maxValue; $value++) {
yield [...$current, $value];
}
if ($elementsCount > 1) {
for ($value = 1; $value <= $maxValue; $value++) {
yield from generate($elementsCount - 1, $maxValue, [...$current, $value]);
}
}
}
Exemple usage + debug/print:
$combinations = generate(3, 3);
print_r(iterator_to_array($combinations, false));
Demo
I have a code like this:
Lets assume that this arrays has this values:
$arr1 = array();
$arr2 = array();
$result = array();
$arr1[] = array( 'grade' => [1,2,3,4] );
$arr2[] = array( 'grade' => [1,2,3,4] );
foreach($arr1 as $a1){
$set1 = $a1['grade'];
foreach($arr2 as $a2){
$set2 = $a2['grade'];
}
$result[] = array('show_result' => $set1+$set2);
}
foreach{$result as $res){
echo $res['show_result'];
}
The output of the array $res['show_result'] must be:
2, 4, 6, 8
But I get the wrong addition of this arrays. Help will be much appreciated.
As Joni said, your first error is on line 3: ' should be ;
Then, you're not filling arrays like you wanted : array( 'grade' => 1,2,3,4 ); creates an array with first key is 'grade' with value '1', then second key is '0' with value '2' etc...
Your last foreach loop has a syntax error similar to your first error.
See a working correction here
$arr1 = array();
$arr2 = array();
$result = array();
array_push($arr1, 1, 2, 3, 4); //fill array with 4 values (integers)
array_push($arr2, 1, 2, 3, 4); //fill array with 4 values (integers)
//so $arr1 & $arr2 are now a 4 elements arrays
$length = count($arr1); //size of array, here 4
for ($i = 0; $i < $length; $i++) { //loop over arrays
array_push($result, ($arr1[$i] + $arr2[$i])); //fill the results array with sum of the values from the same position
}
var_dump($result);
You have quite a few syntax errors in your code.
Although this solution works, the idea behind using the same counter, $i, to extract a value from both arrays is brittle. For example, you'll get an Undefined offset if the first array has 5 grades instead of 4. If you take a step back and explain your problem in the larger context, perhaps we can provide a better solution. I get the sneaking suspicion you're asking an XY Problem.
http://sandbox.onlinephpfunctions.com/code/bb4f492c183fcde1cf4edd50de7ceebf19fe343a
<?php
$gradeList1 = ['grade' => [1,2,3,4]];
$gradeList2 = ['grade' => [1,2,3,4]];
$result = [];
for ($i = 0; $i < count($gradeList1['grade']); $i++) {
$first = $gradeList1['grade'][$i];
$second = $gradeList2['grade'][$i];
$result['show_result'][] = (int)$first + (int)$second;
}
var_dump($result);
This question already has answers here:
Transpose and flatten two-dimensional indexed array where rows may not be of equal length
(4 answers)
Closed 5 months ago.
There are two arrays , the second array will always be smaller by 1 from first array. The first array contains the numbers and second array contains the mathematical operators.
$arr1 = [210,11,12];
$arr2 = ['-','/'];
the code which i have written is working on this test case only ,but when i increase the number of elements in it. It fails.
$arr1 = [210,11,12,12];
$arr2 = ['-','/','/'];
the code i have tried so far..
$arr1 = [210,11,12];
$arr2 = ['-','/'];
$arr3 = [];
for($i=0;$i<count($arr1);$i++){
if($i == 0){
$arr3[] = $arr1[0];
}
if ($i % 2 != 0) {
$arr3[] = $arr1[$i];
}
else {
if($i < (count($arr2)-1)){
$arr3[] = $arr2[$i];
}else{
$arr3[] = $arr2[$i-1];
}
}
}
array_push($arr3,end($arr1));
print_r($arr3);
the expected result will be
$arr3 = [210,'-',11,'/','12','/','12']
You can mix the two arrays together by converting columns to rows with array_map, then merging the rows.
$arr3 = array_merge(...array_map(null, $arr1, $arr2));
array_pop($arr3);
The array_map(null, $arr1, $arr2) expression will result in
[[210, '/'], [11, '/'], [12, '/'], [12, null]]
then, array_merge(...) combines all the inner arrays together into one for the final result.
array_pop will remove the trailing null which is there because of the uneven size of the two arrays, but if you're going to end up imploding this and outputting the results as a math expression, you don't need to do it since that won't show up anyway. In fact, if that is the goal you can just add the implode directly to the expression above.
echo implode(' ', array_merge(...array_map(null, $arr1, $arr2)));
Loop the first array and use $key =>.
Then you build the new array in the loop and if $arr2 has a value with the same key, add it after the $arr1 value.
$arr1 = [210,11,12,12];
$arr2 = ['-','/','/'];
foreach($arr1 as $key => $val){
$arr3[] = $val;
if(isset($arr2[$key])) $arr3[] = $arr2[$key];
}
var_dump($arr3);
//[210, -, 11, /, 12, /, 12]
Provided, as you say, that the second array is always larger by one element, then this would be a simple way to do it:
function foo(array $p, array $q): array {
$r = [array_shift($p)];
foreach ($q as $x) {
$r[] = $x;
$r[] = array_shift($p);
}
return $r;
}
print_r(
foo([210,11,12], ['-', '/'])
);
print_r(
foo([210,11,12,12], ['-','/','/'])
);
https://3v4l.org/F0ud8
If the indices of the arrays are well formed, the above could be simplified to:
function foo(array $p, array $q): array {
$r = [$p[0]];
foreach ($q as $i => $x) {
$r[] = $x;
$r[] = $p[$i + 1];
}
return $r;
}
I wanted to offer a couple of approaches that do not modify the original array, accommodate the possibility of empty input arrays, and do not use more than one loop.
By prepopulating the result array with the first value from the numbers array, then iterating the operators array, you can avoid making iterated checks of isset().
Code: (Demo) (Demo without iterated array_push() calls)
$numbers = [210, 11, 12];
$operators = ['-', '/'];
$result = (array)($numbers[0] ?? []);
foreach ($operators as $i => $operator) {
array_push($result, $operator, $numbers[++$i]);
}
var_export($result);
or with array_reduce():
var_export(
array_reduce(
$operators,
function($result, $operator) use($numbers) {
static $i = 0;
array_push($result, $operator, $numbers[++$i]);
return $result;
},
(array)($numbers[0] ?? [])
)
);
I have two arrays array1 and array2. I want to merge these two arrays into one and show the values of merged array in a dropdown. I want the values in a way that the value of first array - value of 2nd array.
e.g:
$employeePlaces1 = array(1, 2, 4,9);
$employeePlaces2 = array(3, 5, 6,7);
I want in dropdown the value as $employeePlaces1[0]-$employeePlaces2[1],
$employeePlaces1[0]-$employeePlaces2[1].
1-3,
2-5,
4-6,
9-7.
How can I do this ?
$employee1 = array(1, 2, 4, 9);
$employee2 = array(3, 5, 6, 7);
function doMerge($n, $m) {
return $n.'-'.$m;
}
$c = array_map("doMerge", $employee1, $employee2);
print_r($c);
Or in PHP 5.3 syntax with lambda style functions:
$c = array_map(function($n, $m) {return $n.'-'.$m;}, $employee1, $employee2);
You can use the array_diff function
http://www.php.net/manual/en/function.array-diff.php
Answer for the edited question
//assuming both the arrays have the same length
echo "<select>";
for($i=0;$i<count($employeePlaces1);$i++)
{
echo "<option>".$employeePlaces1[i]." - ".$employeePlaces2[i]."</option>";
}
echo "</select>";
How about using array_combine?
http://www.php.net/manual/en/function.array-combine.php
Here is how you could manually loop through them and match the values together.
$list = array();
for($i=0; $i<=count($employeePlaces1); $i++) {
$list[] = $employeePlaces1[$i].'-'.$employeePlaces2[$i];
}
Haven't tested, but should be the gist of what you need.
Why not just loop over the arrays, i.e. do it longhand. Then you can get on with something else!
Edit in response to comment 1:
CakePHP is expecting:
<?php echo $this->Form->input('field', array('options' => array(
'Value 1'=>'Label 1',
'Value 2'=>'Label 2',
'Value 3'=>'Label 3'
))); ?>
so something like (pseudocode):
resultsArray = array();
loop
resultsArray[i] = inputArray_1[i]-inputArray_2[i];
endloop
in PHP (assumes size of array1 <= size of array2):
for($i=0;$i<count($inputArray_1);$i++)
{
$resultsArr[$i] = $inputArray_1[$i]-$inputArray_2[$i];
}
First of all, I'd like to point out to all you duplicate question hunters that this question does not fully answer my question.
Now, I've got an array. We'll say that the array is array(1, 2, 2, 3, 4, 3, 2)
I need to remove the duplicates. Not just one of the duplicates, but all, so that the result will be array(1, 4)
I looked at array_unique(), but that will only result in array(1, 2, 3, 4)
Any ideas?
You could use the combination of array_unique, array_diff_assoc and array_diff:
array_diff($arr, array_diff_assoc($arr, array_unique($arr)))
function removeDuplicates($array) {
$valueCount = array();
foreach ($array as $value) {
$valueCount[$value]++;
}
$return = array();
foreach ($valueCount as $value => $count) {
if ( $count == 1 ) {
$return[] = $value;
}
}
return $return;
}