I want to rotate a matrix 90 degrees clockwise. This amounts to making the first column in the input the first row of the output, the second column of the input the 2nd row of the output, and the 3rd column of the input the 3rd row of the output. Note that the bottom of the column=the beginning of the row, because of the 90 degree rotation.
For example:
$matrix= [[1, 2, 3]
[4, 5, 6],
[7, 8, 9]];
rotate90degrees($matrix)= [[7, 4, 1],
[8, 5, 2],
[9, 6, 3]]
What I know is I have first transpose the matrix and then swap the columns to rotate the matrix by 90 degrees. How can this be applied to php?
I showed you how to transpose an array in answer to a previous question, to rotate 90 degrees, use that transpose logic, and then reverse the order of the values in each row in turn:
$matrix = [
[1, 2, 3],
[4, 5, 6],
[7, 8, 9],
];
array_unshift($matrix, null);
$matrix = call_user_func_array('array_map', $matrix);
$matrix = array_map('array_reverse', $matrix);
var_dump($matrix);
Demo
Another reliable option:
function rotateMatrix90( $matrix )
{
$matrix = array_values( $matrix );
$matrix90 = array();
// make each new row = reversed old column
foreach( array_keys( $matrix[0] ) as $column ){
$matrix90[] = array_reverse( array_column( $matrix, $column ) );
}
return $matrix90;
}
Less clever than #mark-baker's by far. Maybe more clear.
php doesn't have concepts like "transpose" for a matrix without adding some sort of linear algebra library.
you can do it natively by eaching through the matrix and swapping some indexes
<?php
function rotate90($mat) {
$height = count($mat);
$width = count($mat[0]);
$mat90 = array();
for ($i = 0; $i < $width; $i++) {
for ($j = 0; $j < $height; $j++) {
$mat90[$height - $i - 1][$j] = $mat[$height - $j - 1][$i];
}
}
return $mat90;
}
$mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9]];
print_r($mat);
//123
//456
//789
print_r(rotate90($mat));
//741
//852
//963
$mat = [[1, 2, 3], [4, 5, 6], [7, 8, 9], ["a", "b", "c"]];
print_r($mat);
//123
//456
//789
//abc
print_r(rotate90($mat));
//a741
//b852
//c963
You can concisely transpose the matrix data in a one-liner. The ... spread operator unpacks the input array's subarrays into sets of columnar data. Call array_reverse() on the columns of data sent to the custom callback function's scope.
Code: (Demo)
var_export(array_map(fn() => array_reverse(func_get_args()), ...$matrix));
Or:
var_export(array_map(fn(...$col) => array_reverse($col), ...$matrix));
Output (from either):
[[7,4,1],
[8,5,2],
[9,6,3]]
The below code is using additional space.
<?php
function rotate90degrees()
{
$matrix = [[1,2,3],
[4,5,6],
[7,8,9]];
$k = 0;
$len = count($matrix[0]);
$tmp = [];
// Create a new matrix with [[0,0,0],[0,0,0],[0,0,0]]
while($k < $len) {
$row = [];
$l = 0;
while($l < $len) {
$row[] = 0;
$l++;
}
$tmp[] = $row;
$k++;
}
// Rotate through the given matrix and fill out the above created new matrix
for($i=0; $i<$len; $i++) {
for($j=$len-1; $j>=0; $j--) {
$tmp[$i][$j] = $matrix[$j][$i];
}
$tmp[$i] = array_reverse($tmp[$i]);
}
return $matrix;
}
Below function does not use additional space.
<?php
function rotate90degreesWithoutAdditionalSpace()
{
$matrix = [[1,2,3],
[4,5,6],
[7,8,9]];
$len = count($matrix);
// Swap the rows columns.
for($i=0; $i<$len; $i++) {
for($j=$i; $j<$len; $j++) {
$tmp = $matrix[$i][$j];
$matrix[$i][$j] = $matrix[$j][$i];
$matrix[$j][$i] = $tmp;
}
}
// Swap the elements from both ends of each row until the centered element in the row.
for($i=0; $i<$len; $i++) {
for($j=0; $j<floor($len/2); $j++) {
$tmp = $matrix[$i][$j];
$matrix[$i][$j] = $matrix[$i][$len-1-$j];
$matrix[$i][$len-1-$j] = $tmp;
}
}
return $matrix;
}
you can rotate matrix cw using this code:
function rotateCW($arr){
return array_map(function($row, $i) use ($arr){
return array_reverse(array_column($arr, $i));
}, $arr[0], array_keys($arr[0]));
}
and rotate it CCW using this code:
function rotateCCW($arr){
return array_map(function($row, $i) use ($arr){
return array_column($arr, count($arr[0]) - 1 -$i);
}, $arr[0], array_keys($arr[0]));
}
function rotate90($a) {
$cnt = count($a);
$b = $a;
for ($i = 0; $i < $cnt; $i++) {
for ($j = 0; $j < $cnt; $j++) {
$b[$j][$cnt-1-$i] = $a[$i][$j];
}
}
return $b;
}
Related
I have a fixed number (5) and a fixed length (2):
I want to find all the combinations that can sum 50 (this can vary of course).
For example, for 50, and a length of 2, I want to get:
[[1, 49], [2, 48], [3, 47], [4, 46], ...],
For 50 and a length of 4, I want to get:
[[1, 1, 1, 47], [1, 1, 2, 46], [1, 1, 3, 45], [1, 1, 4, 44], ...],
I have no clue how to do this, or whether there's a name in mathematics for this.
This is what I have (doesn't have to use generators):
function getCombinations(array $numbers, int $sum, int $setLength) : \Generator {
$numbersLowestFirst = $numbers;
asort($numbersLowestFirst);
$lowestNumber = 0;
foreach ($numbersLowestFirst as $number) {
// array might be associative and we want to preserve the keys
$lowestNumber = $number;
break;
}
$remainingAmount = $sum - $lowestNumber;
$remainingNumberofItems = $setLength - 1;
$possibleItemCombinations = array_pad([$remainingAmount], $remainingNumberofItems, $lowestNumber);
}
I first made it using JS then translated to PHP. See below for a JS demonstration. The idea is as #Barmar said in comments.
Note: There will be duplicates. If you care for that, you should sort each "triplet" and look for duplications. See JS solution for that below.
function getCombinations($sum, $n)
{
if ($n == 1) {
return [[$sum]];
}
$arr = [];
for ($i = 0; $i <= $sum / 2; $i++) {
$combos = getCombinations($sum - $i, $n - 1);
foreach ($combos as $combo) {
$combo[] = $i;
$arr[] = $combo;
}
}
return ($arr);
}
JS style, it's the same idea only more comfortable to test on browser.
function getCombinations(sum, n) {
if (n == 1) return [[sum]];
var arr = []
for (var i = 0; i <= sum / 2; i++) {
var combos = getCombinations(sum - i, n - 1)
combos.forEach(combo => {
arr.push([i, ...combo]);
})
}
// removing duplicates
arr = Object.values(arr.reduce(function(agg, triplet) {
triplet = triplet.sort();
agg["" + triplet] = triplet;
return agg;
}, {}))
return arr;
}
console.log(getCombinations(5, 3))
I have array with positive int values like [4, 1, 75, 52, 5, 24]. I need to find two values with minimal difference. Also, I need the original keys of those two. So, I sorted the array with asort() to keep the keys. Now when I iterate I have a problem - I can't use $key + 1 to point to next element and using next() and prev() makes it difficult to get the keys (once you use next or prev pointer is moved):
for ($i = 0; $i < count($sorted)-1; $i++) {
if (current($sorted) - next($sorted) < $min) {
//echo prev($sorted) - next($sorted) . '<br>';
}
}
What would you do?
(Feel free to alter array in any other form if that makes this easier - asort is not necessary)
If I need to explain one more time: I have a problem with keys. Finding the closest values is not a problem.
I completely revamped your snippet. You can take whatever you want from below snippet,
$array = [4, 1, 5, 52, 75, 52, 24];
function difference($arr)
{
$n = count($arr);
// Initialize difference
// as infinite
$diff = PHP_INT_MAX;
// Find the min diff by comparing
// difference of all possible
// pairs in given array
$two_values = [];
for ($i = 0; $i < $n - 1; $i++) {
for ($j = $i + 1; $j < $n; $j++) {
if (abs($arr[$i] - $arr[$j]) < $diff) {
$diff = abs($arr[$i] - $arr[$j]);
$two_values['values'] = [$arr[$i], $arr[$j]];
$two_values['keys'] = [$i, $j];
$two_values['diff'] = $diff;
}
}
}
// Return min diff
return $two_values;
}
print_r(difference($array));
Demo.
Please let me know if something is not getting.
I found my own way to do this using additional array with keys and array_multisort()
$numbers = [4, 1, 75, 1, 52, 5, 52, 24, 52];
$ar = [];
$mins = [];
$min = PHP_INT_MAX;
foreach ($numbers as $key => $number) {
$ar[] = ['key' => $key, 'number' => $number];
}
array_multisort(array_column($ar, 'number'), SORT_DESC, array_column($ar, 'key'), SORT_DESC, $ar );
foreach ($ar as $key => $value) {
if (!isset($ar[$key + 1])) break;
if ($value['number'] - $ar[$key + 1]['number'] <= $min) {
$min = $value['number'] - $ar[$key + 1]['number'];
$mins = [$ar[$key + 1], $ar[$key]];
}
}
I want to merge / mix two arrays together, but I want it to be randomly "mixed" however NOT shuffled. For example:
$first = [1, 2, 3, 4];
$second = [10, 20, 30, 40];
Possible desired "mixes" are:
[1, 10, 20, 30, 2, 40, 3, 4]
[10, 1, 2, 20, 30, 3, 4, 40]
[1, 2, 3, 10, 20, 4, 30, 40]
Note that if we pluck the values back out we would still have the original orders of:
1, 2, 3, 4
10, 20, 30, 40
Well, there's (yet another) one possible approach:
$arr = call_user_func_array('array_merge', array_map(null, $first, $second));
print_r($arr); // [1, 10, 2, 20, 3, 30, 4, 40];
Demo. That's apparently deterministic; for random ordering each pair should be shuffled additionally. For example:
function zipShuffle($first, $second) {
return call_user_func_array('array_merge', array_map(function($a, $b) {
return mt_rand(0, 1) ? [$a, $b] : [$b, $a];
}, $first, $second));
}
... but that obviously won't be able to churn out something like [1,2,3,10,20...]. If this is required, here's another solution:
function orderedShuffle($first, $second) {
$results = [];
$stor = [$first, $second];
$i = mt_rand(0, 1);
// switching between arrays on the fly
while (list(, $v) = each($stor[$i])) {
$results[] = $v;
$i = mt_rand(0, 1);
}
// one array is gone, now we need to add all the elements
// of the other one (as its counter left where it was)
$i = 1 - $i;
while (list(, $v) = each($stor[$i])) {
$results[] = $v;
}
return $results;
}
Demo. The last function is actually quite easy to extend for as many arrays as required.
Can you try this,
<?php
$first = array(1,2,3,4);
$second = array(10,20,30,40);
$arrayMixed=array();
$firstReverse=array_reverse($first);
$secondReverse=array_reverse($second);
$firstReverseCount = count($firstReverse);
$secondReverseCount = count($secondReverse);
foreach($firstReverse as $key=>$val) {
if ($firstReverseCount>0) {
array_push($arrayMixed, array_pop($firstReverse));
if ($secondReverseCount>0) {
array_push($arrayMixed, array_pop($secondReverse));
}
}
}
$ArrayMixeddata = array_merge($arrayMixed, $second);
echo "<pre>";
print_r($ArrayMixeddata);
echo "</pre>";
?>
Not quick ways, but them works.
// with permutations
function combineShuffleOrder($first, $second)
{
// combine into one array with alternation
$firstLen = count($first);
$secondLen = count($second);
$max = max($firstLen, $secondLen);
$result = array();
for($i=0; $i < $max; $i++) {
if ($i < $firstLen)
$result[] = $first[$i];
if ($i < $secondLen)
$result[] = $second[$i];
}
// "shuffle" with permutation
$len = count($result);
for($i=1; $i<$len; $i++) {
if (rand(1, 3) % 2 == 0) {
$tmp = $result[$i-1];
$result[$i-1] = $result[$i];
$result[$i] = $tmp;
$i++; // skip one exchange
}
}
return $result;
}
// with using "shuffle" in subarray
function combineShuffleOrder2($first, $second)
{
// combine into one array with alternation
$firstLen = count($first);
$secondLen = count($second);
$max = max($firstLen, $secondLen);
$result = array();
for($i=0; $i < $max; $i++) {
$sub = array();
if ($i < $firstLen)
$sub[] = $first[$i];
if ($i < $secondLen)
$sub[] = $second[$i];
shuffle($sub);
$result = array_merge($result, $sub);
}
return $result;
}
// with using "shuffle" in subarray if sources arrays are equals by length
function combineShuffleOrder3($first, $second)
{
$max = count($first);
$result = array();
for($i=0; $i < $max; $i++) {
$sub = array(
$first[$i],
$second[$i]
);
shuffle($sub);
$result = array_merge($result, $sub);
}
return $result;
}
$first = array(1,2,3,4);
$second = array(10,20,30,40);
print_r(combineShuffleOrder($first, $second));
print_r(combineShuffleOrder2($first, $second));
print_r(combineShuffleOrder3($first, $second));
I recommend forming a single array of the two input arrays for simpler toggling. Simply loop and consume one element from a randomly selected array and push that selection into the result array. When the pool of arrays is reduced to a single array, kill the loop and append the remaining elements of the last surviving array onto the result array.
I'll use a pool of four arrays (one which is empty from the beginning) to demonstrate that the snippet is robust enough to handle a variable number of arrays, a variable number of elements in each array, and empty arrays.
Code: (Demo)
$first = [1, 2, 3, 4];
$second = [10, 20, 30, 40];
$third = [];
$fourth = ['a', 'b'];
$pool = [$first, $second, $third, $fourth];
$result = [];
while (count($pool) > 1) {
$pullFrom = array_rand($pool);
if (!$pool[$pullFrom]) {
unset($pool[$pullFrom]);
continue;
}
$result[] = array_shift($pool[$pullFrom]);
}
var_export(array_merge($result, ...$pool));
Alternatively without array_merge() and count() calls, but it makes more iterated calls of array_shift(): (Demo)
$pool = [$first, $second, $third, $fourth];
$result = [];
while ($pool) {
$pullFrom = array_rand($pool);
if (!$pool[$pullFrom]) {
unset($pool[$pullFrom]);
continue;
}
$result[] = array_shift($pool[$pullFrom]);
}
var_export($result);
Loop this script until both arrays are done.
$j = 0;
$i = 0;
$r = rand(0, 1);
if($r == 0) {
$ret .= $array1[$i];
$i++;
} elseif($r == 1) {
$ret .= $array2[$j];
$j++;
}
Of course, you have to handle a few exceptions in this code, but it might be the route.
I have this array:
$a = array(1, 2, 3, 4, 5, 7, 8, 10, 12);
Is there a function to convert this to:
$b = array(1, 1, 1, 1, 2, 1, 2, 2);
So basicaly:
$b = array ($a[1]-$a[0], $a[2]-$a[1], $a[3]-$a[2], ... ,$a[n]-$a[n-1]);
Here is the code I have so far:
$a = $c = array(1, 2, 3, 4, 5, 7, 8, 10, 12);
array_shift($c);
$d = array();
foreach ($a as $key => $value){
$d[$key] = $c[$key]-$value;
}
array_pop($d);
There isn't a built-in function that can do this for you, but you could turn your code into one instead. Also, rather than making a second array, $c, you could use a regular for loop to loop through the values:
function cumulate($array = array()) {
// re-index the array for guaranteed-success with the for-loop
$array = array_values($array);
$cumulated = array();
$count = count($array);
if ($count == 1) {
// there is only a single element in the array; no need to loop through it
return $array;
} else {
// iterate through each element (starting with the second) and subtract
// the prior-element's value from the current
for ($i = 1; $i < $count; $i++) {
$cumulated[] = $array[$i] - $array[$i - 1];
}
}
return $cumulated;
}
I think php has not a build in function for this. There are many ways to solve this, but you already wrote the answer:
$len = count($a);
$b = array();
for ($i = 0; $i < $len - 1; $i++) {
$b[] = $a[$i+1] - $a[$i];
}
This question already has answers here:
PHP get the item in an array that has the most duplicates
(2 answers)
Closed 1 year ago.
I have an array of numbers like this:
$array = array(1,1,1,4,3,1);
How do I get the count of most repeated value?
This should work:
$count=array_count_values($array);//Counts the values in the array, returns associatve array
arsort($count);//Sort it from highest to lowest
$keys=array_keys($count);//Split the array so we can find the most occuring key
echo "The most occuring value is $keys[0][1] with $keys[0][0] occurences."
I think array_count_values function can be useful to you. Look at this manual for details : http://php.net/manual/en/function.array-count-values.php
You can count the number of occurrences of values in an array with array_count_values:
$counts = array_count_values($array);
Then just do a reverse sort on the counts:
arsort($counts);
Then check the top value to get your mode.
$mode = key($counts);
If your array contains strings or integers only you can use array_count_values and arsort:
$array = array(1, 1, 1, 4, 3, 1);
$counts = array_count_values($array);
arsort($counts);
That would leave the most used element as the first one of $counts. You can get the count amount and value afterwards.
It is important to note that if there are several elements with the same amount of occurrences in the original array I can't say for sure which one you will get. Everything depends on the implementations of array_count_values and arsort. You will need to thoroughly test this to prevent bugs afterwards if you need any particular one, don't make any assumptions.
If you need any particular one, you'd may be better off not using arsort and write the reduction loop yourself.
$array = array(1, 1, 1, 4, 3, 1);
/* Our return values, with some useless defaults */
$max = 0;
$max_item = $array[0];
$counts = array_count_values($array);
foreach ($counts as $value => $amount) {
if ($amount > $max) {
$max = $amount;
$max_item = $value;
}
}
After the foreach loop, $max_item contains the last item that appears the most in the original array as long as array_count_values returns the elements in the order they are found (which appears to be the case based on the example of the documentation). You can get the first item to appear the most in your original array by using a non-strict comparison ($amount >= $max instead of $amount > $max).
You could even get all elements tied for the maximum amount of occurrences this way:
$array = array(1, 1, 1, 4, 3, 1);
/* Our return values */
$max = 0;
$max_items = array();
$counts = array_count_values($array);
foreach ($counts as $value => $amount) {
if ($amount > $max) {
$max = $amount;
$max_items = array($value);
} elif ($amount = $max) {
$max_items[] = $value;
}
}
$vals = array_count_values($arr);
asort($vals);
//you may need this end($vals);
echo key($vals);
I cant remember if asort sorts asc or desc by default, you can see the comment in the code.
<?php
$arrrand = '$arr = array(';
for ($i = 0; $i < 100000; $i++)
{
$arrrand .= rand(0, 1000) . ',';
}
$arrrand = substr($arrrand, 0, -1);
$arrrand .= ');';
eval($arrrand);
$start1 = microtime();
$count = array_count_values($arr);
$end1 = microtime();
echo $end1 - $start1;
echo '<br>';
$start2 = microtime();
$tmparr = array();
foreach ($arr as $key => $value);
{
if (isset($tmparr[$value]))
{
$tmparr[$value]++;
} else
{
$tmparr[$value] = 1;
}
}
$end2 = microtime();
echo $end2 - $start2;
Here check both solutions:
1 by array_count_values()
and one by hand.
<?php
$input = array(1,2,2,2,8,9);
$output = array();
$maxElement = 0;
for($i=0;$i<count($input);$i++) {
$count = 0;
for ($j = 0; $j < count($input); $j++) {
if ($input[$i] == $input[$j]) {
$count++;
}
}
if($count>$maxElement){
$maxElement = $count;
$a = $input[$i];
}
}
echo $a.' -> '.$maxElement;
The output will be 2 -> 3
$arrays = array(1, 2, 2, 2, 3, 1); // sample array
$count=array_count_values($arrays); // getting repeated value with count
asort($count); // sorting array
$key=key($count);
echo $arrays[$key]; // get most repeated value from array
String S;
Scanner in = new Scanner(System.in);
System.out.println("Enter the String: ");
S = in.nextLine();
int count =1;
int max = 1;
char maxChar=S.charAt(0);
for(int i=1; i <S.length(); i++)
{
count = S.charAt(i) == S.charAt(i - 1) ? (count + 1):1;
if(count > max)
{
max = count;
maxChar = S.charAt(i);
}
}
System.out.println("Longest run: "+max+", for the character "+maxChar);
here is the solution
class TestClass {
public $keyVal;
public $keyPlace = 0;
//put your code here
public function maxused_num($array) {
$temp = array();
$tempval = array();
$r = 0;
for ($i = 0; $i <= count($array) - 1; $i++) {
$r = 0;
for ($j = 0; $j <= count($array) - 1; $j++) {
if ($array[$i] == $array[$j]) {
$r = $r + 1;
}
}
$tempval[$i] = $r;
$temp[$i] = $array[$i];
}
//fetch max value
$max = 0;
for ($i = 0; $i <= count($tempval) - 1; $i++) {
if ($tempval[$i] > $max) {
$max = $tempval[$i];
}
}
//get value
for ($i = 0; $i <= count($tempval) - 1; $i++) {
if ($tempval[$i] == $max) {
$this->keyVal = $tempval[$i];
$this->keyPlace = $i;
break;
}
}
// 1.place holder on array $this->keyPlace;
// 2.number of reapeats $this->keyVal;
return $array[$this->keyPlace];
}
}
$catch = new TestClass();
$array = array(1, 1, 1, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 3, 1, 2, 3, 1, 1, 2, 5, 7, 1, 9, 0, 11, 22, 1, 1, 22, 22, 35, 66, 1, 1, 1);
echo $catch->maxused_num($array);