如何排序数组包含复杂的字符串与PHP中的分数?

时间:2018-03-30 18:57:50

标签: php arrays sorting fractions

我在数组中有以下值,

$values = array(
            "1/4x1/4x1", 
            "1/2x1/2x1", 
            "3/4x3/4x1", 
            "1/4x1/4x2", 
            "1/2x1/2x2", 
            "3/4x3/4x2", 
            "1x1x1", 
            "1x2x1", 
            "2x1x1"
        );

考虑到'x'之间的数字,我希望值的升序如下,

$values = array(
            "1/4x1/4x1", 
            "1/4x1/4x2", 
            "1/2x1/2x1", 
            "1/2x1/2x2", 
            "3/4x3/4x1", 
            "3/4x3/4x2", 
            "1x1x1", 
            "1x2x1",
            "2x1x1"
        );

我是PHP的新手。这有什么特定的功能吗?如果没有,请帮助找到解决方案。感谢。

2 个答案:

答案 0 :(得分:0)

这有点复杂,但您可以避免使用eval

// Transpose resulting 2x2 matrix using array_map behavior of
// tacking an arbitrary number of arrays and zipping elements, when null
// giving as a callback.
$evaluated = array_map(null, ...array_map(function ($factors) {
    return array_map(function ($factor) {
        // Explode fraction (into array with two elements)
        // and destruct it into variables.
        // `@` will silent the notice if not a fraction given (array with one
        // element).
        @list($dividend, $divisor) = explode('/', $factor); // **

        // If divisor is given then calculate a fraction.
        return $divisor
            ? floatval($dividend) / floatval($divisor)
            : floatval($dividend);
    }, explode('x', $factors));
}, $values));

// Assign values array by reference as a last element.
$evaluated[] =& $values;

// Unpack all arrays (three columns of fractions and given array) and pass
// them to `array_multisort` function, that will sort in turns by each of
// the columns.
array_multisort(...$evaluated);

print_r($values);

因此,基本上,我们将数组中的每个项目映射到计算分数的数组中,然后转换此数组,最后得到三个表示列的数组。然后我们将这三个数组与给定数组一起传递给array_multisort,它通过引用获取给定数组并根据需要重新排序。

这是the demo

答案 1 :(得分:0)

不要使用eval()!这是邪恶的。你可以轻松地避免它。您需要为usort()创建一个回调方法,用于比较维度(如果需要,可以将分数转换为数值)。

我假设你总是有3个维度,它们是正整数或分数。我还假设您没有按体积排序,而是按尺寸1,尺寸2,尺寸3进行排序。

/**
 * usort callback to sort dimensions
 * @param {string} $a first comparable value
 * @param {string} $b second comparable value
 * @returns {int} 0, 1 or -1
 */
function sortByDimension($a, $b) {
    $dimA = getNumericDimensions($a);
    $dimB = getNumericDimensions($b);

    // first dimension is the same: compare deeper
    if ($dimA[0] == $dimB[0]) {
        // second dimension is the same too: compare deeper
        if ($dimA[1] == $dimB[1]) {
            if ($dimA[2] == $dimB[2]) {
                // value is the same: return 0
                return 0;
            }
            // value A is larger: return 1, value B is larger: return -1
            return ($dimA[2] > $dimB[2]) ? 1 : -1;
        }           
        return ($dimA[1] > $dimB[1]) ? 1 : -1;
    }
    return ($dimA[0] > $dimB[0]) ? 1 : -1;
}

/**
 * converts a string value to an array of numeric values
 * @param {string} $val string of dimensions AxBxC
 * @returns {array} an array with 3 dimensions and numeric values
 */
function getNumericDimensions($val) {
    // split the value into the 3 dimensions
    $dimensions = explode('x', $val);

    // loop through the values and make them numeric
    // note: the loop is per reference: we override the values!
    foreach ($dimensions as &$dim) {        
        // check if it is a fraction
        if (strpos($dim, '/') !== false) {
            // split the fraction by the /
            $fraction = explode('/', $dim);
            // calculate a numeric value
            $dim = $fraction[0] / $fraction[1];
        } else {
            // make it an integer
            $dim = (int)$dim;
        }
    }
    return $dimensions;
}

$values = array(
        "1/4x1/4x1", 
        "1/2x1/2x1", 
        "3/4x3/4x1", 
        "1/4x1/4x2", 
        "1/2x1/2x2", 
        "3/4x3/4x2", 
        "1x1x1", 
        "1x2x1", 
        "2x1x1",
    );

// sort the array (note: usort is per reference)
usort($values, 'sortByDimension');
print_r($values);