I have a task of sorting an array of numbers in both ascending and descending order. The challenge is, I can't use the built-in sort function, but loop through the array with for-loops instead.
I am a total newbie when it comes to PHP and this task straight off baffles me. Here is the code I'm supposed to work with:
<?php
$arr = $_GET['arr'];
$table = explode(',', $arr);
$count = count($table);
// What I tried to work with, didn't get to work:
for ($i = 0; $i < $count; $i++) {
for ($j = $i + 1; $j < $count; $j++) {
if ($table[$i] > $table[$j]) {
$temp = $table[$i];
$table[$i] = $table[$j];
$table[$j] = $temp;
$asc = implode("," $temp);
}
}
}
echo "Ascending: $asc";
echo "Descending: $desc";
?>
Any clue why this doesn't run? At some point, I got the first (largest) number in the array with the echo, but don't really know what broke that either.
Move the line
$asc = implode(",", $table);
from its current location below the outer for loop and maybe add the line
$desc = implode(",", array_reverse($table));
to get the descending sort order.
Many ways to make it. One solution you will find in the code below. you will certainly notice that the sorting depends only on one operator. Therefore, you can build a function out of it by specifying the sorting as a parameter. function(array $array, string $sort) {}
DESC
$arr= array(112,21,130,140,2,42);
for($i=0; $i<count($arr)-1; $i++)
{
for($j=0; $j<count($arr)-1; $j++)
{
if($arr[$j] < $arr[$j+1]){
$temp= $arr[$j+1];
$arr[$j+1]= $arr[$j];
$arr[$j]= $temp;
}
}
}
print_r($arr);
Output:
Array
(
[0] => 140
[1] => 130
[2] => 112
[3] => 42
[4] => 21
[5] => 2
)
ASC
$arr= array(112,21,130,140,2,42);
for($i=0; $i<count($arr)-1; $i++)
{
for($j=0; $j<count($arr)-1; $j++)
{
if($arr[$j] > $arr[$j+1]){
$temp= $arr[$j+1];
$arr[$j+1]= $arr[$j];
$arr[$j]= $temp;
}
}
}
print_r($arr);
Output
Array
(
[0] => 2
[1] => 21
[2] => 42
[3] => 112
[4] => 130
[5] => 140
)
Related
This question already has answers here:
How can I sort arrays and data in PHP?
(14 answers)
Closed 3 years ago.
I am trying to create an algorithm that shows each step of bubble sort, sorting one number at a time. I was was able to sort the number at the first index, but I need to figure out how to sort all the numbers.
$x = array (9,7,5,3,0);
$count = count($x);
for($i = 0; $i < $count-1; $i++ ) {
$temp = $x[$i+1];
$x[$i+1] = $x[$i];
$x[$i] = $temp;
echo '<pre>';
print_r($x);
}
My current output is:
Array
(
[0] => 7
[1] => 9
[2] => 5
[3] => 3
[4] => 0
)
Array
(
[0] => 7
[1] => 5
[2] => 9
[3] => 3
[4] => 0
)
Array
(
[0] => 7
[1] => 5
[2] => 3
[3] => 9
[4] => 0
)
Array
(
[0] => 7
[1] => 5
[2] => 3
[3] => 0
[4] => 9
)
From here I need to continue sorting the remaining numbers. For 7, the output should be
57390
53790
53970
53907
and then for 3
35079
30579
30759
30795
and then for 0, it should be same for all 4 lines like
03570
03579
03579
03579
[The assigned problem.][1]
Two issues:
You should only swap values when they are not in the right order
You need an outer loop to repeat this inner loop, similar to a proper bubble sort algorithm.
Your code can be modified like below so it generates the required output:
$x = array (9,7,5,3,0);
$count = count($x) - 1;
for($times = 0; $times < $count; $times++) {
for($i = 0; $i < $count; $i++ ) {
$temp = $x[$i+1];
if ($temp < $x[$i]) {
$x[$i+1] = $x[$i];
$x[$i] = $temp;
}
echo implode(" ", $x) . "\n";
}
echo "\n";
}
Note that a proper bubble sort algorithm will perform fewer iterations.
Bubble sort is basically simplified into a min() + shift (or sometimes swap) operation that occurs N times. So it's an O(n^2) algorithm.
Since this is for learning purposes I'm going to try to be as verbose as possible.
function getMin(Array &$array): Int {
$min = reset($array);
$minKey = null;
// Find the minimum value
foreach($array as $k => $n) {
if ($n < $min) {
$min = $n;
$minKey = $k;
}
}
// remove the minimum value from the array
$array[$k] = null;
$array = array_filter($array, function ($v) { return $v !== null; });
return $min;
}
$array = [9,7,5,3,0];
foreach ($array as $n => $value) {
// Find the min value in the array from Nth index onward
$min = getMin($array); // get the smallest value in the array and remove it.
$sorted[] = $min; // push it on to the new array
}
var_dump($sorted);
This gives you the expect result:
array(5) {
[0]=>
int(0)
[1]=>
int(3)
[2]=>
int(5)
[3]=>
int(7)
[4]=>
int(9)
}
Of course, this is not the way you would want to implement Bubble Sort, because it's a bit circuitous. Again, it's for educational purposes. You can inspect the $array as it's being modified at each step and the new $sorted as it's being built. Typically you would just swap the min/max values in place and use the same array (keeping track of the keys to rescan the array).
Like this...
// Unsorted $array
$array = [9,7,5,3,0];
// Sort the array
for ($lastKey = $i = 0, $len = count($array); $i < $len; $i++) {
// Scan for minimum value
for ($minKey = $j = $lastKey, $min = $array[$minKey]; $j < $len; $j++) {
if ($array[$j] < $min) {
$minKey = $j;
$min = $array[$j];
}
}
// Swap the values
$swap = $array[$lastKey];
$array[$lastKey] = $min;
$array[$minKey] = $swap;
// Update the scan position
$lastKey++;
}
var_dump($array); // Gives you [0,3,5,7,9]
You are performing unconditional position swapping, but you actually need to check if movement is required.
There is no shortage of tutorials that demonstrate a bubble sort in php. A quick good lead me to this one: https://www.w3resource.com/php-exercises/searching-and-sorting-algorithm/searching-and-sorting-algorithm-exercise-6.php which can be modified for your purposes.
PHP now offers "array destructuring" which means you no longer need to use a temporary holding variable while swapping.
Code: (Demo)
$x = [9,7,5,3,0];
$count = count($x) - 1;
for ($pass = 0; $pass < $count; ++$pass) {
for ($i = 0; $i < $count; ++$i) {
if ($x[$i] > $x[$i + 1]) {
[$x[$i + 1], $x[$i]] = [$x[$i], $x[$i + 1]];
}
$results[] = implode($x);
}
$results[] = "\n";
}
echo implode("\n", $results);
I have a simple array that looks like this:
Array (
[0] => Array (
[id] => 8692
[name] => d
)
[1] => Array (
[id] => 8691
[name] => c
)
[2] => Array (
[id] => 8690
[name] => b
)
[3] => Array (
[id] => 8689
[name] => a
)
[4] => Array (
[id] => 8500
[name] => d
)
[5] => Array (
[id] => 8499
[name] => c
)
[6] => Array (
[id] => 8498
[name] => b
)
[7] => Array (
[id] => 8497
[name] => a
)
)
This array is quite long so I only included the first 4 items to give you an idea.
My problem is that I need the array to be in a format of
a,b,c,d,a,b,c,d
At the moment the format is like:
d,c,b,a,d,c,b,a
By this I mean the ['name'] value which is either a,b,c or d.
So I every 4 items in the array need to be reversed.
I have tried to achieve this but fail every time ending up with lots of for & while loops.
You can do it using array_chunk, array_merge and array_reverse:
$finalArray = array();
$arrays = array_chunk($myArray, 4);
foreach ($arrays as $array) {
$finalArray = array_merge($finalArray, array_reverse($array));
}
All the answers here, while perfectly valid, are pretty much on the order of O(n^2). So I figured I'd give you an O(n / 2), time complexity, solution as an alternative just in case you care about performance. The solution also uses only O(n + n + k) space complexity (in place swap).
Since the requirement is to reverse order of values, I'm ignoring keys and basing the solution on the constraint that the array is always 0-indexed.
To solve this problem, we can generalize the solution as a simple array reverse, which requires a simple O(n/2) operation with in-place swap. We can achieve this simply with two counters, $i starting from the beginning of the array, and $j starting at the end of the array. Thus, we can swap the values at $arr[$i] with that at $arr[$j] and then increment $i and decrement $j, at each step.
function reverseArray(Array $arr) {
for($i = 0, $j = count($arr); $i < $j; $i++, $j--) {
$tmp = $arr[$j];
$arr[$j] = $arr[$i];
$arr[$i] = $tmp;
}
return $arr;
}
Now, to apply the more specific solution of only reverse every group of 4 elements in the array, we just break up the array in partitions of 4 values, and only reverse each of those partitions at a time. Which just expands on the example above of reverseArray() by altering the starting and ending positions of the $i and $j counter to only reverse within each partition.
Thus we arrive the O(n / 2) solution here by just adding another loop for the partition size, and keep the inner loop from the earlier example.
function reverseArrayPartition(Array $arr, $partitionSize = 4) {
$end = count($arr);
// reverse only one partition at a time
for($start = 0; $start < $end; $start += $partitionSize ) {
$from = $start;
$to = $start + $partitionSize - 1;
for($i = $from, $j = $to; $i < $j; $i++, $j--) {
// swap the transposing values
$tmp = $arr[$j];
$arr[$j] = $arr[$i];
$arr[$i] = $tmp;
}
}
return $arr;
}
$arr = [4,3,2,1,4,3,2,1];
var_dump(reverseArrayPartition($arr)); // expected [1,2,3,4,1,2,3,4]
This will work with any array size at any $partitionSize so it's efficient if you're trying to do this on very large arrays.
You can iterate the array with a for and increment with 4 each time and keep the current offset in other variable and use array_slice to get the current slice of array and reverse order using array_reverse
I am thinking of something like this:
$step = 4;
$offset = 0;
$new_arr = []; //Here we create the new array.
for($i=0; $i<count($arr); $i+=$step) {
$part_of_array = array_slice($arr, $offset, $step);
$part_reverse = array_reverse($part_of_array);
$new_arr = array_merge($new_arr, $part_reverse);
$offset += $step;
}
print_r($new_arr); //Here will be the array as you expected.
All the content in the for can be simplify to:
$new_arr = array_merge($new_arr, array_reverse(array_slice($arr, $offset, $step)));
$offset += $step;
Not harcoding every 4, reverse based on char code of name value
<?php
error_reporting(E_ALL);
ini_set('display_errors', 1);
/**
*/
$in = [
['name'=>'d','id'=>1]
, ['name'=>'c','id'=>12]
, ['name'=>'b','id'=>13]
, ['name'=>'a','id'=>14]
, ['name'=>'d','id'=>15]
, ['name'=>'c','id'=>16]
, ['name'=>'b','id'=>17]
, ['name'=>'a','id'=>18]
];
$last = PHP_INT_MAX;
$toReverse = [];
$out = [];
foreach ($in as $value) {
$p = ord($value['name']);
if ( $p < $last ) {
//echo 'ToReverse',var_export($value,true),"\n";
$toReverse[] = $value;
}
else {
$out = array_merge($out,array_reverse($toReverse));
//echo 'Join',var_export($out,true),"\n";
$toReverse = [$value];
}
$last = $p;
}
$out = array_merge($out,array_reverse($toReverse));
print_r($out);
So i have array like this and sometimes it has very similar entries:
Array
(
[0] => greys anatomy
[1] => element 3d
[2] => interstellar
[3] => monster ball
[4] => scorpion
[5] => taken 3
[6] => the flash
[7] => wild card
[8] => big bang theory
[9] => the big bang theory
[10] => fredrik kempe vincero
[11] => fredrik kempe vicero
)
I would like to remove similar entries that are longer ones. So for example in this array: [9] => the big bang theory and [10] => fredrik kempe vincero entries should be removed. as they are similar to 8th and 11th entry, but longer.
EDIT:
So if anyone needs, I made working solution out of two answers below:
function check_similar($first, $second)
{
similar_text($first, $second, $percent);
if ($percent >= 80) { //needed percent value
return true;
}
else {
return false;
}
}
for ($i = 0; $i < count($array); $i++) {
for ($j = $i; $j < count($array); $j++) {
if ($j > $i && check_similar($array[$i],$array[$j]) == true) {
$array[$j] = null;
}
}
}
// filter array to remove null values and reindex
$array = array_values(array_filter($array));
print_r($array);
String similarity is a very difficoult problem that cannot be solved easily. There are several complex approaches, but none can be effective as if it was made by a human being.
Take a look on php soundhex and levenshtein which could be an easy solution for your particular case.
In any case, given a custom function that defines or not if a string is similar to another, to make your array unique you have to do something like:
// set to null all subsequent similar strings
for ($i = 0; $i < count($array); $i++) {
for ($j = $i; $j < count($array); $j++) {
if ($j > $i && similar($array[$i],$array[$j])) {
$array[$j] = null;
}
}
}
// filter array to remove null values
$array = array_filter($array);
Take a look at the similar_text function.
similar_text('the big bang theory','big bang theory', $percent);
echo $percent; // 88%
This is obviously more difficult than it seems, but can do this check while making this array.
See this link for an alternate implementation.
I want to create an array from this nested for loop
for($i = 0; $i < 2; $i++){
for($j = 0; $j < 3; $j++){
$dis = $i + $j;
createArr($dis, $i);
}
echoArr($i);
}
To do this I created a function called createArr() which receives $dis and the $i iterator.
$arr= array();
function createArr($dis, $i){
$arr= 'arr'.$i;
array_push($arr, $dis);
return $arr;
}
I want $arr to be the name of the array in this example during the first iteration of the nested for loop $i = 0. Thus I want the name of the array to be $arr0 with the array_push function pushing all the elements of $j while $i = 0 then to store into another array when the second iteration of $i when it starts at$arr1 to push the new elements of this array within $j's iteration when $i = 1;
function echoArr($i){
$arr= 'arr'.$i;
return $arr;
}
this last function is to echo the finished array after an iteration of $i is done.
I am not sure what you are expecting
$arr= 'arr'.$i;
array_push($arr, $dis);
to do, but array_push expects first parameter to be array,
but as you can see $arr is a string.
Is this what you need?
$arr = array();
for($i = 0; $i < 2; $i++){
for($j = 0; $j < 3; $j++){
$dis = $i + $j;
array_push($arr, createArr($dis, $i));
}
echoArr($i);
}
function createArr($dis, $i){
return array('arr'.$i => $dis);
}
print_r($arr);
//prints: Array ( [0] => Array ( [arr0] => 0 ) [1] => Array ( [arr0] => 1 ) [2] => Array ( [arr0] => 2 ) [3] => Array ( [arr1] => 1 ) [4] => Array ( [arr1] => 2 ) [5] => Array ( [arr1] => 3 ) )
What are you trying to achieve?
For the future pls describe what you would like to achieve so we can help you achieve it better.
Let me start with the first piece of code
You would like to echo the array. You are just echoing the column.
why build your own function to add something to an array?
and if you to do something with the return
$myarray[$i] = createArr($key,$value); //not a good solution, just for explaining.
Since I don't know what you like to achieve here an example of an array loop
$myarray = array();
for($i = 0; $i < 2; $i++){
for($j = 0; $j < 3; $j++){
$dis = $i + $j;
$myarray[$i][$j] = 'row:' . $i . ' column' . $j;
}
}
var_dump($myarray);
and the dump
array (size=2)
0 =>
array (size=3)
0 => string 'row:0 column0' (length=13)
1 => string 'row:0 column1' (length=13)
2 => string 'row:0 column2' (length=13)
1 =>
array (size=3)
0 => string 'row:1 column0' (length=13)
1 => string 'row:1 column1' (length=13)
2 => string 'row:1 column2' (length=13)
What I need to accomplish is,
I have an array, 2 3 4 5 6 7 8 9 10
I need to check if any numbers in the array divides any other number in the array perfectly. (%=0) If yes, unset the the number.
Its over my head and I cant get it working and everything I tried gives me infinite loops and its making me ill. (lol)
I am not including any codes, because all I could come up with is a nested forloop which doesnt work :(
So here is a sample :
Input array :2 3 4 5 6 7 8
Output = 5 6 7 8
Any idea guys?
UPDATE:
Cracked the nut myself with bit more debugging. (Incase if that can be helpful for someone in future.)
// use array_unique, array_values and $size = sizeof($array)
for ($i = 0; $i < $size; $i++)
{
for ($j = $size - 1; $j > $i; $j--)
if ($numbers[$j] % $numbers[$i] == 0)
{
unset($numbers[$i]);
break;
}
}
I will not do this in real code, just because I think you want to do that yourself.
LoopA iterating the intput array:
LoopB iterating the input array:
check division of loopA value and loopB value, and add the value of loopA to a new array accordingly
End loopB
End loopA
Print the new array
Note: This is not complete, but it certainly should give you a start on how to continue.
For sorted ordered number
$arr = array(2,3,4,5,6,7,8,9,10,11,12,13,14);
$half_c = ceil(count($arr)/2) - 1;
$result_array = array_slice($arr, $half_c);
Edit: For random array you can cut half again, and iterate only first part of array. Prime number theory also can help to write faster algorithm for first part of array.
How about:
$arr = range(2,20);
$size = count($arr);
for ($i=0; $i<$size; $i++) {
for ($j=$size-1; $j>$i; $j--) {
if ($arr[$j]%$arr[$i]) continue;
unset($arr[$i]);
break;
}
}
print_r($arr);
output:
Array
(
[9] => 11
[10] => 12
[11] => 13
[12] => 14
[13] => 15
[14] => 16
[15] => 17
[16] => 18
[17] => 19
[18] => 20
)
Try this:
for($i = 0; $i < count($arr); $i++)
{
for($j = 0; $j < count($arr); $j++)
{
if($arr[$i] != $arr[$j] && $arr[$i] % $arr[$j] === 0)
{
unset($arr[$j);
break;
}
}
}