在单独的数组中按值子字符串对 PHP 数组进行排序

问题描述 投票:0回答:3

我正在使用 WordPress 提供的

get_posts
来提供一组帖子对象。该数组的简化版本如下;

$zones = array
    0 => 
        object
            public 'post_title' => string 'Zone Five: Banana'
    1 => 
        object
            public 'post_title' => string 'Zone Eight: Banana'
    2 => 
        object
            public 'post_title' => string 'Zone Six: Banana'
    3 => 
        object
            public 'post_title' => string 'Zone Seven: Banana'
    4 => 
        object
            public 'post_title' => string 'Zone Four: Cherry'
    5 => 
        object
            public 'post_title' => string 'Zone Two: Orange'
    6 => 
        object
            public 'post_title' => string 'Zone Three: Avocado'
    7 => 
        object
            public 'post_title' => string 'Zone One: Apple'

如您所见,帖子标题不按顺序排列。显然按字母顺序排序是行不通的。

理想情况下,数组的第一项是

Zone One: Apple
,最后一项是
Zone Eight: Banana

我认为

usort
将是要使用的 PHP 函数,但我不知道如何比较子字符串而不是整个字符串。

这里是一些适用于全文匹配的代码; (借自另一个有用的堆栈溢出帖子)

$order = array_flip(['Zone One: Apple', 'Zone Two: Orange', 'Zone Three: Avocado', 'Zone Four: Cherry', 'Zone Five: Banana', 'Zone Six: Banana', 'Zone Seven: Banana', 'Zone Eight: Banana']); // restructure with values as keys, and keys as order (ASC)

$outlier = 1 + max($order);

usort($zones, function ($a, $b) use (&$order, $outlier) { // make $order modifiable with &
    if (!isset($order[$a->post_title])) {$order[$a->post_title] = $outlier;} // update lookup array with [id]=>[outlier number]
    if (!isset($order[$b->post_title])) {$order[$b->post_title] = $outlier;} // and again
        return $order[$a->post_title] <=> $order[$b->post_title];
});

理想情况下,我想按子字符串排序;

$order = ['一', '二', '三', '四', '五', '六', '七', '八'];

php arrays usort
3个回答
0
投票

请注意,下面的代码旨在为您提供一个示例,说明您可以做什么。下面的代码最多只能工作到十。如果你有 11 个或什么都没有,它的行为可能是未定义的。

对于您的问题,您需要将数字解析为实际 int 值的单词并进行比较。因此,您需要以某种方式从字符串中获取数字作为单词。因此,您需要一个将数字作为单词到 int 值的字典。

如果您运行的代码使用正则表达式来查找每个可能的数字单词的字符串,那么这可能会很困难。另一个解决方案是,如果您的标题始终以“zone”开头,然后是“number”,然后是“:”。您可以 split 或 substr 或任何您认为有效的方法。这是最困难的部分。但在那之后,一切都是轻而易举的事情。

找到该数字单词后,将其转换为 int 值并对它们进行比较并适当地使用该值。

需要考虑的一件事是,如果数组中的字符串之一不包含数字会发生什么?

<?php
$order = ['Zone One: Apple', 'Zone Two: Orange', 'Zone Three: Avocado', 'Zone Four: Cherry', 'Zone Five: Banana', 'Zone Six: Banana', 'Zone Seven: Banana', 'Zone Eight: Banana']; // restructure with values as keys, and keys as order (ASC)
shuffle($order); // Shuffle the array

// Acending = true                == smaller is smaller
// Acending = false == descending == smaller is bigger
function cmpStrWithNumberWord($str1, $str2, $ascending = true ){
    $numbers = ['one' => 1, 
               'two' => 2,
               'three' => 3,
               'four' =>4,
               'five' =>5,
               'six' =>6,
               'seven' =>7,
               'eight' => 8,
               'nine' => 9,
               'ten' => 10];

    $regex = '/\b(' . implode('|',array_keys($numbers)) . ')\b/iU';

    $str1n = 0;
    $str2n = 0;

    preg_match($regex, $str1, $str1);
    preg_match($regex, $str2, $str2);

    if ( count($str1) > 1 )
        $str1n = $numbers[strtolower($str1[0])];
    if ( count($str2) > 1 )
        $str2n = $numbers[strtolower($str2[0])];

    if ( $ascending === true ){
        if ( $str1n === $str2n ) return 0;
        return $str1n < $str2n? -1 : 1;
    } else {
        if ( $str1n === $str2n ) return 0;
        return $str1n > $str2n? -1 : 1;
    }
}

var_dump($order); // Print the shuffled array.

usort($order, 'cmpStrWithNumberWord' );
var_dump($order); // Sorted array

0
投票

这确实假设所有数据都是按照您所说的方式构建的,因为没有任何检查来确保数据的格式正确。它还依赖于 PHP 7+ 进行小型思考,例如比较中的宇宙飞船运算符 (

<=>
)...

$zones = ['Zone Seven: Banana', 'Zone Eight: Banana',
    'Zone Four: Cherry', 'Zone Five: Banana', 'Zone Six: Banana', 
    'Zone One: Apple', 'Zone Two: Orange', 'Zone Three: Avocado', 
    ];
shuffle($zones);

usort($zones, function ($a, $b) {
    static $sort = ['zero' => 0, 'one' => 1, 'two' => 2, 'three' => 3, 'four' => 4,
        'five' => 5, 'six' => 6, 'seven' => 7, 'eight' => 8, 'nine' => 9, 'ten' => 10
    ];

    $a1 = explode(" ", explode(":", $a)[0])[1];
    $b1 = explode(" ", explode(":", $b)[0])[1];

    return $sort[strtolower($a1)] <=> $sort[strtolower($b1)];
});

print_r($zones);

0
投票

子字符串提取是最笨重的部分。在这种情况下,您不需要对查找数组进行硬编码,因为有一个本机库可供使用。

通过解析原始值的中间词来填充新的整数数组将告诉

array_multisort()
如何对值进行排序。

代码:(演示

$f = new NumberFormatter("en", NumberFormatter::SPELLOUT);

array_multisort(
    array_map(fn($s) => $f->parse(lcfirst(strstr(substr($s, 5), ':', true))), $zones),
    $zones
);
var_export($zones);
© www.soinside.com 2019 - 2024. All rights reserved.