Сортировать массив PHP по значению подстроки по порядку в отдельном массиве - PullRequest
1 голос
/ 10 октября 2019

Я использую get_posts, предоставленный WordPress, для предоставления массива почтовых объектов. Упрощенная версия этого массива выглядит следующим образом:

$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 = ['One', 'Two', 'Three', «Четыре», «Пять», «Шесть», «Семь», «Восемь»];

Ответы [ 2 ]

0 голосов
/ 10 октября 2019

Это предполагает, что все данные структурированы так, как вы говорите, поскольку нет никаких проверок, чтобы гарантировать, что данные имеют правильный формат. Он также полагается на 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 голосов
/ 10 октября 2019

Обратите внимание, что приведенный ниже код должен дать вам пример того, что вы можете сделать. Этот код ниже будет работать только до десяти. Если у вас одиннадцать или ничего нет, его поведение может быть неопределенным.

Для вашей проблемы вам нужно проанализировать число в виде слов с фактическим значением int и сравнить их. Таким образом, вам нужно каким-то образом получить число в виде слов из строки. Таким образом, вам нужен словарь чисел в качестве слов для значений int.

Это может быть сложно, если вы запустите код, который использует регулярные выражения для каждого возможного слова, являющегося числом. Другое решение, если ваш заголовок всегда начинается с «зоны», а затем с «номера», а затем «:». Вы можете разделить или использовать метод, который вы считаете эффективным. Это сложная часть. Но после этого это ветер.

Как только вы нашли это числовое слово, вы преобразовали его в значения 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
...