Sorting an array with bubble sort [duplicate] - php

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);

Related

Sorting an array of numbers with for-loop

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
)

Make binary Pairing array from dynamic associative array on the basis of Keys, One Element from each Key

I'm Basically Creating Pair from a dynamic associative array in such a manner that I took 1 element from one key array and other element from other key array on which these two elements combine make pair 1. Problem is this a dynamic associative array it can have 4 Keys having arrays every key can have maximum two elements and minimum 1 elememt in its array and to make pair we should have two keys having 1 element on both side of these two keys array.
For Example
[parent_id] => Array
(
[9] => Array
(
[0] => 11
[1] => 12
)
[10] => Array
(
[0] => 13
[1] => 14
)
[20] => Array
(
[0] => 21
[1] => 22
)
[21] => Array
(
[0] => 23
)
)
This is an associative array which gives 3 pairs right now.
For Example
pair 1 contain: 11 , 13
pair 2 contain: 12 , 14
pair 3 contain: 21 , 23
Now the Issue is by using what methodology I can get my desire result.
Any Suggestions !!!!
Update 3
The last update didn't find all the possible pairs for one case. This version loops through differently, taking at most one element from each array before moving to the next one and pairing from there. It loops until there are insufficient values left to pair.
function find_pairs($array) {
// re-index to 0
$array = array_values($array['parent_id']);
// sort so the longest arrays are first
usort($array, function ($a, $b) { return count($b) - count($a); });
// output array
$pairs = array();
$c = count($array);
$i = 0;
// loop while there are enough values to pair (2 or more)
while (array_reduce($array, function ($c, $v) { return $c + count($v); }, 0) > 1) {
// make sure there are some elements in this array
while (!count($array[$i])) $i = ($i + 1) % $c;
// find the next array with a value
$j = ($i + 1) % $c;
while (!count($array[$j])) $j = ($j + 1) % $c;
// have we come full circle?
if ($j == $i) break;
// save the pair
$pairs[] = array(array_shift($array[$i]), array_shift($array[$j]));
// move on to the next array
$i = ($i + 1) % $c;
}
return $pairs;
}
Demo (includes all possible test cases) on 3v4l.org
Original answer
Here's one way to do this. Re-index the parent_id array to start at 0, and then loop through the array 2 elements at a time, combining all the values from each element. We use min to make sure we only pair as many values as there are in the smallest value array.
// re-index to 0
$array = array_values($array['parent_id']);
// output array
$pairs = array();
for ($i = 0; $i < count($array) - 1; $i += 2) {
for ($j = 0; $j < min(count($array[$i]), count($array[$i+1])); $j++) {
$pairs[] = array($array[$i][$j], $array[$i+1][$j]);
}
}
print_r($pairs);
Output:
Array (
[0] => Array ( [0] => 11 [1] => 13 )
[1] => Array ( [0] => 12 [1] => 14 )
[2] => Array ( [0] => 21 [1] => 23 )
)
Demo on 3v4l.org
Update
If you want to guarantee getting the maximum number of pairs from the array, sort to make the longest arrays come first:
$array = array_values($array['parent_id']);
// sort so the longest arrays are first
usort($array, function ($a, $b) { return count($b) - count($a); });
// output array
$pairs = array();
for ($i = 0; $i < count($array) - 1; $i += 2) {
for ($j = 0; $j < min(count($array[$i]), count($array[$i+1])); $j++) {
$pairs[] = array($array[$i][$j], $array[$i+1][$j]);
}
}
print_r($pairs);
Demo on 3v4l.org
Update 2
Based on further comments, it seems the only requirement for pairing is that the key of the array from which the elements from is not the same. This makes things a bit more complicated, but this function should do what you want:
function find_pairs($array) {
// re-index to 0
$array = array_values($array['parent_id']);
// sort so the longest arrays are first
usort($array, function ($a, $b) { return count($b) - count($a); });
// output array
$pairs = array();
for ($i = 0, $j = 1; $i < count($array) - 1; $i++) {
if (!count($array[$i])) continue;
while ($j <= $i || $j < count($array) && !count($array[$j])) $j++;
while (count($array[$i]) && isset($array[$j]) && count($array[$j])) {
$pairs[] = array(array_shift($array[$i]), array_shift($array[$j]));
// exhausted other arrays elements?
while ($j < count($array) && !count($array[$j])) $j++;
}
}
return $pairs;
}
Demo on 3v4l.org

How to get the factorial value of each number in an array?

I am trying to get an factorial value of each item in array by using this method but this outputs only one value
can any body help me finding where i am doing wrong?
function mathh($arr, $fn){
for($i = 1; $i < sizeof($arr); $i++){
$arr2 = [];
$arr2[$i] = $fn($arr[$i]);
}
return $arr2;
}
$userDefined = function($value){
$x = 1;
return $x = $value * $x;
};
$arr = [1,2,3,4,5];
$newArray = mathh($arr, $userDefined);
print_r($newArray);
You're going to need a little recursion so in order to do that you need to pass the lambda function into itself by reference:
function mathh($arr, $fn){
$arr2 = []; // moved the array formation out of the for loop so it doesn't get overwritten
for($i = 0; $i < sizeof($arr); $i++){ // starting $i at 0
$arr2[$i] = $fn($arr[$i]);
}
return $arr2;
}
$userDefined = function($value) use (&$userDefined){ // note the reference to the lambda function $userDefined
if(1 == $value) {
return 1;
} else {
return $value * $userDefined($value - 1); // here is the recursion which performs the factorial math
}
};
$arr = [1,2,3,4,5];
$newArray = mathh($arr, $userDefined);
print_r($newArray);
The output:
Array
(
[0] => 1
[1] => 2
[2] => 6
[3] => 24
[4] => 120
)
I wanted to expand on this some since you're essentially (in this case) creating an array map. This could be handy if you're doing additional calculations in your function mathh() but if all you want to do is use the lambda function to create a new array with a range you could do this (utilizing the same lambda we've already created):
$mapped_to_lambda = array_map($userDefined, range(1, 5));
print_r($mapped_to_lambda);
You will get the same output, because the range (1,5) of the mapped array is the same as your original array:
Array
(
[0] => 1
[1] => 2
[2] => 6
[3] => 24
[4] => 120
)

sorting array without php built-in sort function

I am very newbie on programming, first studying PHP language about arrays. I can sort an array with sort function, but I got stuck here.
If i have input array(1,3,5,6,7,8,11,12,17,11)
I try to get output 12 or bigger number 2, but if I do print_r($array[i] - 1);
I just get 10-1=9. how can i get value 12?
and then if I have input array(1,2,3,5,6) I try to get output false because of the missing number 4.
I make sort function:
for(int j:0;j<=count($array) ;j++) {
for(int i:0;i<=count($array[i+1]);i++{
if($array[i]>$array[$+1]{
$temp=$array[$i+1];
$array[$i+1]=$array[$i];
$array[$i]=temp;
}
}
}
print_r($array) ;
Thanks if someone can help me or teach me? :)
You have a lot of syntax errors in your code. Check the comments under your question, they pretty much covered it.
To sort an array with a custom sort you can use this:
$array = array(1,3,5,6,7,8,11,12,17,11);
$arrayCount = count($array); // no need to evaluate the count on every iteration of the for loop
for($i=0; $i < $arrayCount - 1; $i++)
{
for($j = $i+1; $j < $arrayCount; $j++)
{
// if you want the array sorted from bigger to smaller number use `>` here
if($array[$j] < $array[$i])
{
$temp = $array[$i];
$array[$i] = $array[$j];
$array[$j] = $temp;
}
}
}
print_r($array);
which outputs:
Array
(
[0] => 1
[1] => 3
[2] => 5
[3] => 6
[4] => 7
[5] => 8
[6] => 11
[7] => 11
[8] => 12
[9] => 17
)
Now to retrieve a desired value from the array or false if it does not exist you would write something like this using the built in array_search() method:
// Check if array contains a value 12, if it does return the index location in the array
// returns false if the value is not found
$index = array_search(12, $array);
if($index === false)
{
echo 'Value does not exist in the array.';
}
else
{
echo 'Value '.$array[$index].' is at index '.$index.' in the array.';
}

How to reverse PHP array in partitions

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);

Categories