Advertisement
shapoval

Sorting blog posts - every 3rd should be featured post

Aug 17th, 2018
195
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
PHP 7.58 KB | None | 0 0
  1. <?php
  2. /*
  3. Sorting blog posts - every third place should be taken only by a featured post
  4. */
  5.  
  6. echo '<style type="text/css"> p { margin: 10px 0 0; } .success { color: #070; } .error { color: #F66; }</style>';
  7.  
  8. class Category {
  9.     public $id;
  10.     public $is_featured = false;
  11.    
  12.     public function __construct($id, $is_featured = false) {
  13.         $this->id = $id;
  14.         $this->is_featured = $is_featured;
  15.     }
  16. }
  17.  
  18. class Post {
  19.     public $id;
  20.     public $category;
  21.  
  22.     public function __construct($id, $category) {
  23.         $this->id = $id;
  24.         $this->category = $category;
  25.     }
  26.  
  27.     public static function sort($posts, $groupLength = 3) {
  28.         $moveElementInArray = function(&$array, $fromIndex, $toIndex) {
  29.             array_splice($array, $toIndex, 0, array_splice($array, $fromIndex, 1));
  30.         };
  31.  
  32.         $sortedPosts = $posts;
  33.  
  34.         for ($index = 0; $index < count($posts); $index++) {
  35.             $post = $sortedPosts[$index];
  36.  
  37.             /* If we don't need a featured post here or this post is a featured - leave it as is */
  38.             if ($index % 3 !== 0 || $post->category->is_featured) {
  39.                 continue;
  40.             }
  41.  
  42.             $featuredPostPlaces = [];
  43.             foreach ($sortedPosts as $i => $p) {
  44.                 if ($p->category->is_featured) {
  45.                     $featuredPostPlaces[$i] = $p;
  46.                 }
  47.             }
  48.  
  49.             /* Check if we have enough featured posts */
  50.             $groupNumber = floor($index / $groupLength);
  51.             if ($groupNumber < count($featuredPostPlaces)) {
  52.  
  53.                 /* We should split featured posts into two groups - prevous posts and next posts.
  54.                    We should take the closest post from group which have a suitable post. */
  55.  
  56.                 /* Check if we have enough featured posts on previous items */
  57.                 $previousFeaturedPostPositions = array_filter(array_keys($featuredPostPlaces), function($position) use ($index) { return $position < $index; });
  58.                 $closestPreviousFeaturedPostPosition = null;
  59.                 if (count($previousFeaturedPostPositions) > $groupNumber) {
  60.                     $closestPreviousFeaturedPostPosition = max($previousFeaturedPostPositions);
  61.                 }
  62.  
  63.                 /* Check if we have featured posts on next items */
  64.                 $nextFeaturedPostPositions = array_filter(array_keys($featuredPostPlaces), function($position) use ($index) { return $position > $index; });
  65.                 $closestNextFeaturedPostPosition = null;
  66.                 if (count($nextFeaturedPostPositions) > 0) {
  67.                     $closestNextFeaturedPostPosition = min($nextFeaturedPostPositions);
  68.                 }
  69.  
  70.                 if ( $closestPreviousFeaturedPostPosition !== null &&
  71.                           ($closestNextFeaturedPostPosition === null || abs($closestPreviousFeaturedPostPosition - $index) < abs($closestNextFeaturedPostPosition - $index)) ) {
  72.                     /* Featured element to move is on previous elements */
  73.  
  74.                     $moveElementInArray($sortedPosts, $closestPreviousFeaturedPostPosition, $index);
  75.  
  76.                     /* We need to sort previous elements again */
  77.                     $resortedPreviousElements = self::sort(array_slice($sortedPosts, 0, $index - 1));
  78.                     $sortedPosts = array_merge($resortedPreviousElements, array_slice($sortedPosts, $index - 1));
  79.                 } elseif ($closestNextFeaturedPostPosition !== null) {
  80.                     /* Featured element to move is on next elements */
  81.                     $moveElementInArray($sortedPosts, $closestNextFeaturedPostPosition, $index);
  82.                 }
  83.             }
  84.         }
  85.  
  86.         return array_values($sortedPosts);
  87.     }
  88. }
  89.  
  90. $categories = [
  91.     1 => new Category(1, true),
  92.     2 => new Category(2, true),
  93.     3 => new Category(3, false),
  94. ];
  95.  
  96. $posts = [
  97.     // Featured
  98.     1 => new Post(1, $categories[1]),
  99.     2 => new Post(2, $categories[1]),
  100.     3 => new Post(3, $categories[1]),
  101.     4 => new Post(4, $categories[1]),
  102.     5 => new Post(5, $categories[1]),
  103.     6 => new Post(6, $categories[2]),
  104.     7 => new Post(7, $categories[2]),
  105.     8 => new Post(8, $categories[2]),
  106.     9 => new Post(9, $categories[2]),
  107.  
  108.     // Usual
  109.     10 => new Post(10, $categories[3]),
  110.     11 => new Post(11, $categories[3]),
  111.     12 => new Post(12, $categories[3]),
  112.     13 => new Post(13, $categories[3]),
  113.     14 => new Post(14, $categories[3]),
  114.     15 => new Post(15, $categories[3]),
  115.     16 => new Post(16, $categories[3]),
  116.     17 => new Post(17, $categories[3]),
  117.     18 => new Post(18, $categories[3]),
  118.     19 => new Post(19, $categories[3]),
  119.     20 => new Post(20, $categories[3]),
  120. ];
  121.  
  122. $tests = [
  123.     [
  124.         'input'  => [],
  125.         'output' => [],
  126.     ],
  127.  
  128.     [
  129.         'input'  => [1, 2, 3, 4, 5, 6],
  130.         'output' => [1, 2, 3, 4, 5, 6],
  131.     ],
  132.    
  133.     [
  134.         'input'  => [1, 2, 3, 4, 10, 11],
  135.         'output' => [1, 2, 3, 4, 10, 11],
  136.     ],
  137.  
  138.     [
  139.         'input'  => [10, 11, 12, 13, 14, 15, 16],
  140.         'output' => [10, 11, 12, 13, 14, 15, 16],
  141.     ],
  142.  
  143.     [
  144.         'input'  => [1, 2, 3, 4, 10, 11, 12, 13, 14],
  145.         'output' => [1, 2, 10,   3, 11, 12,   4, 13, 14],
  146.     ],
  147.  
  148.     [
  149.         'input'  => [1, 2, 10, 11, 12, 13],
  150.         'output' => [1, 10, 11,   2, 12, 13],
  151.     ],
  152.  
  153.     [
  154.         'input'  => [10, 11, 12, 13, 1, 2],
  155.         'output' => [1, 10, 11,   2, 12, 13],
  156.     ],
  157.  
  158.     [
  159.         'input'  => [10, 11, 12, 13, 14, 1, 2],
  160.         'output' => [1, 10, 11,   2, 12, 13, 14],
  161.     ],
  162.  
  163.     [
  164.         'input'  => [10, 11, 12, 13, 14, 15, 1, 2, 3],
  165.         'output' => [1, 10, 11,   2, 12, 13,   3, 14, 15],
  166.     ],
  167.  
  168.     [
  169.         'input'  => [10, 11, 12, 13, 14, 15, 1, 2],
  170.         'output' => [1, 10, 11,   2, 12, 13,   14, 15],
  171.     ],
  172.  
  173.     [
  174.         'input'  => [10, 11, 12, 13, 14, 15, 1, 2],
  175.         'output' => [1, 10, 11,   2, 12, 13,   14, 15],
  176.     ],
  177.  
  178.     [
  179.         'input'  => [10, 11, 12, 13, 14, 15, 16, 1, 2],
  180.         'output' => [1, 10, 11,   2, 12, 13,   14, 15, 16],
  181.     ],
  182.  
  183.     [
  184.         'input'  => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18],
  185.         'output' => [1, 2, 3,    4, 5, 10,    6, 11, 12,    7, 13, 14,    8, 15, 16,   9, 17, 18],
  186.     ],
  187.  
  188.     [
  189.         'input'  => [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16, 17, 18, 19],
  190.         'output' => [1, 2, 3,    4, 10, 11,    5, 12, 13,    6, 14, 15,    7, 16, 17,   8, 18, 19, 9],
  191.     ],
  192.  
  193.     [
  194.         'input'  => [1, 2, 10, 11, 3, 4, 5, 12, 6, 13, 14, 15, 7, 16, 8, 17, 18, 19, 9],
  195.         'output' => [1, 2, 10,    3, 11, 4,  5, 12, 13,    6, 14, 15,    7, 16, 17,   8, 18, 19, 9],
  196.     ],
  197. ];
  198.  
  199. foreach ($tests as $index => $test) {
  200.     $result = Post::sort(array_values( array_map(function($id) use ($posts) { return $posts[$id]; }, $test['input']) ));
  201.  
  202.     $inputIds = $test['input'];
  203.     $expectedOutputIds = $test['output'];
  204.     $realOutputIds = array_map(function($post) { return $post->id; }, $result);
  205.  
  206.     $outputDiff = array_diff_assoc($expectedOutputIds, $realOutputIds);
  207.  
  208.     if (empty($outputDiff)) {
  209.         echo "<p class='success'>Test #{$index}: SUCCESS</p>";
  210.     } else {
  211.         echo "<p class='error'>Test #{$index}: ERROR.";
  212.             echo "<table>";
  213.                 echo "<tr><td>Input:</td><td>" . json_encode($inputIds) . "</td></tr>";
  214.                 echo "<tr><td>Output:</td><td>" . json_encode($realOutputIds) . "</td></tr>";
  215.                 echo "<tr><td>Expected Output:</td><td>" . json_encode($expectedOutputIds) . "</td></tr>";
  216.             echo "</table>";
  217.         echo "</p>";
  218.     }
  219. }
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement