【问题标题】:Sort PHP array by value substring by order in separate array按单独数组中的顺序按值子字符串对 PHP 数组进行排序
【发布时间】:2020-02-07 10:51:43
【问题描述】:

我正在使用 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


【解决方案1】:

请注意,下面的代码旨在为您提供一个示例,说明您可以做什么。下面的代码最多只能工作十个。如果你有 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

【讨论】:

    【解决方案2】:

    这确实假设所有数据的结构都如您所说,因为没有任何检查来确保数据的格式正确。它还依赖 PHP 7+ 来进行比较,比如太空飞船操作员 (&lt;=&gt;)...

    $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);
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2010-12-12
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2012-05-16
      • 2012-06-02
      相关资源
      最近更新 更多