过滤包含模块和软件版本值的行并保留具有最高版本的唯一模块

Filter rows containing modules and software version values and retain unique modules with highest version

我有一个这样的数组:

Array (
    [vendor] => Array (
        [0] => Array ( [name] => module-one [version] => 1.7.0 )
        [1] => Array ( [name] => module-one [version] => 1.8.0 )
        [2] => Array ( [name] => module-two [version] => 1.8.0 )
        [3] => Array ( [name] => module-two [version] => 1.2.0 )
        [4] => Array ( [name] => module-three [version] => 1.9.0 )
        [5] => Array ( [name] => module-three [version] => 1.8.0 )
    )
)

我想通过键 name 比较数组,如果匹配则获取可用的最高版本,如下所示:

Array (
    [vendor] => Array (
        [0] => Array ( [name] => module-one [version] => 1.8.0 )
        [1] => Array ( [name] => module-two [version] => 1.8.0 )
        [2] => Array ( [name] => module-three [version] => 1.9.0 )
    )
)

尝试这样的事情

// assuming your array is called $rows

$latest_modules = [];

foreach ($rows as $row) {
   $name = $row['name'];
   $version = $row['version'];

   if (empty($latest_modules[$name]) || ($latest_modules[$name] < $version))  {
         $latest_modules[$name] = $version;
   }
}

print_r($latest_modules);

-- 更新

@nice_dev 指出比较不适用于所有版本情况。

例如,1.12.1 与 1.2.1 将 return 1.2.1 作为更大的版本,这是不正确的。

 // assuming your array is called $rows

$latest_modules = [];

foreach ($rows as $row) {
    $name = $row['name'];
    $version = $row['version'];

    if (empty($latest_modules[$name])) {
        $latest_modules[$name] = $version;
    }
    else {
        $latest_modules[$name] = max_version($latest_modules[$name], $version);
    }
}

print_r($latest_modules);


function max_version($a, $b) {
    $a_parts = explode('.', $a);
    $b_parts = explode('.', $b);

    if (count($a_parts) !== count($b_parts)) {
        throw new \Exception('Both versions must be in same format major.minor.bugfix');
    }

    foreach ($a_parts as $key => $a_val) {
        $b_val = $b_parts[$key] ?? 0;

        if ($a_val > $b_val) {
            return $a;
        }
        elseif ($b_val > $a_val) {
            return $b;
        }
        // $a_val and $b_val are equal, continue through look at check next value.
    }

    // both values are the same, doesn't matter which one we return
    return $a;
}

PHP 有一个 native version comparison function 让这项工作变得非常简单。按 name 值分组,当您遇到与特定组匹配的任何后续行时 - 如果版本更高,则只保存新行。

我已经更改了您的示例输入以表明多位数版本值将得到正确处理。

代码:(Demo)

$vendor = [
    [ "name" => "module-one", "version" => "1.7.0" ],
    [ "name" => "module-one", "version" => "1.8.0" ],
    [ "name" => "module-two", "version" => "1.8.0" ],
    [ "name" => "module-two", "version" => "1.12.0" ],
    [ "name" => "module-three", "version" => "1.9.0" ],
    [ "name" => "module-three", "version" => "1.8.0" ],
];

$result = [];
foreach ($vendor as $row) {
    if (
        !isset($result[$row['name']])
        || version_compare($result[$row['name']]['version'], $row['version'], '<')
    ) {
        $result[$row['name']] = $row;
    }
}
var_export(array_values($result));

输出:

array (
  0 => 
  array (
    'name' => 'module-one',
    'version' => '1.8.0',
  ),
  1 => 
  array (
    'name' => 'module-two',
    'version' => '1.12.0',
  ),
  2 => 
  array (
    'name' => 'module-three',
    'version' => '1.9.0',
  ),
)