Search code examples
phparrayssemantic-versioning

How to filter an array keeping the highest patch version in each minor version?


I have following array:


array(174) {
  [0]=>
  string(5) "3.0.3"
  [1]=>
  string(5) "3.0.2"
  [2]=>
  string(5) "3.0.1"
  [3]=>
  string(5) "3.0.0"
  [9]=>
  string(5) "2.9.5"
  [10]=>
  string(5) "2.9.4"
  [11]=>
  string(5) "2.9.3"
  [12]=>
  string(5) "2.9.2"
  [13]=>
  string(5) "2.9.1"
  [14]=>
  string(5) "2.9.0"
  [18]=>
  string(6) "2.8.11"
  [19]=>
  string(6) "2.8.10"
  [20]=>
  string(5) "2.8.9"
}

I need to find the highest 3rd number for unique pair of first two numbers x.x. With this example the expected result must be:

3.0.3, 2.9.5, 2.8.11

This is what I tried:

foreach ($array as $key => $value) {
    $test = substr($value, 0, 3);
    $a = strtr($value, array('.' => '', ',' => ''));
    $b = (int) $a;
    $c = substr($b, 0, 2);
    $new_array = array($c);
    $result = array_unique($new_array);
    print_object($result);
}

Solution

  • First you must group the versions by the major version. After that you just need to sort the resulted groups using the version_compare function in a descending order and to return the first element of each group:

    $versions = array("3.0.3", "3.0.2", "3.0.1", "3.0.0", "2.9.5", "2.9.4",
        "2.9.3", "2.9.2", "2.9.1", "2.9.0", "2.8.11", "2.8.10", "2.8.9"
    );
    
    $groupedVersions = array();
    foreach ($versions as $version) {
        preg_match('/^\d+\.\d+/', $version, $majorVersion);
        if (!isset($groupedVersions[$majorVersion[0]])) {
            $groupedVersions[$majorVersion[0]] = array($version);
        } else {
            $groupedVersions[$majorVersion[0]][] = $version;
        }
    }
    
    $groupedVersions = array_map(function ($versions) {
        usort($versions, 'version_compare');
        return array_reverse($versions);
    }, $groupedVersions);
    
    $latestVersions = array_reduce($groupedVersions, function ($carry, $versions) {
        $carry[] = $versions[0];
        return $carry;
    }, array());
    
    echo '<pre>';
    var_dump($latestVersions);
    echo '</pre>';
    

    The result would be:

    array(3) {
      [0]=>
      string(5) "3.0.3"
      [1]=>
      string(5) "2.9.5"
      [2]=>
      string(6) "2.8.11"
    }