PHP own array of sorting strings according to several criteria

I have an array of font names that comes to me in width and then in weight (in alphabetical order). The standard width does not have an indicator inside the line, as well as other widths (compressed, extended, etc.). This is what the array looks like when I get it:

Array ( 
[0] => Bold 
[1] => ExtraBold 
[2] => ExtraLight 
[3] => Light 
[4] => Medium 
[5] => Regular 
[6] => SemiBold 
[7] => Thin 
[8] => Condensed Bold 
[9] => Condensed ExtraBold 
[10] => Condensed ExtraLight 
[11] => Condensed Light 
[12] => Condensed Medium 
[13] => Condensed Regular 
[14] => Condensed SemiBold 
[15] => Condensed Thin 
[16] => Expanded Black 
[17] => Expanded Bold 
[18] => Expanded ExtraBold 
[19] => Expanded ExtraLight 
[20] => Expanded Light 
[21] => Expanded Medium 
[22] => Expanded Regular 
[23] => Expanded SemiBold 
[24] => Expanded Thin) 

I need to sort it first according to this width order:

$order_array_crit_one = array("Expanded", "Standard", "Condensed");

And then according to the weight in that order:

$order_array_crit_two = array("Black", "ExtraBold", "Bold", "SemiBold", "Medium", "Regular", "Light", "Thin", "ExtraLight");

I somehow managed to use a sorting function that compared words ( like this ), but every solution I've come up with so far has been cumbersome and confusing.

+4
source share
4 answers

, , . , , . , , :

// 3 items need 2 bits to be represented:
// ( 0 => 00 => "Expanded", 1 => 01 => "Standard", 2 => 10 => "Condensed" )
$crit1 = ["Expanded", "Standard", "Condensed"];
// 9 items need 4 bits to be represented:
// ( 0 => 0000 => "Black", ... 8 => 1000 => "ExtraLight" )
$crit2 = ["Black", "ExtraBold", "Bold", "SemiBold", "Medium", "Regular", "Light", "Thin", "ExtraLight"];
// if you join all the bits, each item of your array can be represented with a 6
// bits number:
// ( 0 => 000000 => "Expanded Black" ... 40 => 101000 => "Condensed ExtraLight" )

$crit2 = array_flip($crit2);

$result = [];

foreach ($arr as $item) {
    if (false !== strpos($item, "Expanded"))
        $key = 0;  // 000000
    elseif (false !== strpos($item, "Condensed"))
        $key = 32; // 100000
    else
        $key = 16; // 010000

    $parts = explode(' ', $item);
    $weight = isset($parts[1]) ? $parts[1] : $parts[0];
    $key += $crit2[$weight];

    $result[$key] = $item;
}

ksort($result, SORT_NUMERIC);
$result = array_values($result);

print_r($result);

+1

Array FontName, , , , , , . .

//pseudo-code

class FontName {
  //member variables - can use getters and setters if you want
  name;
  width;
  weight;
  length;
}

sort(FontNameArray, propertyname) {
   // use reflection to get the value of propertyname from the FontName object
   // sort by that value
}
0

, "" " ", , , :

$font_details = function($font) use ($order_array_crit_one, $order_array_crit_two) {
    $matches = explode(' ', $font);
    $details = new StdClass();

    $details->crit_one = (count($matches) > 1) ? $matches[0] : 'Standard';
    $details->crit_one_position = array_search($details->crit_one, $order_array_crit_one);
    $details->crit_two = (count($matches) > 1) ? $matches[1] : $matches[0];
    $details->crit_two_position = array_search($details->crit_two, $order_array_crit_two);

    return $details;
};

// $fonts is your input array $fonts = array('Bold', 'ExtraBold',...
usort($fonts, function($a, $b) use($font_details) {
    $a_details = $font_details($a);
    $b_details = $font_details($b);

    if($a_details->crit_one_position < $b_details->crit_one_position) return -1;
    if($a_details->crit_one_position > $b_details->crit_one_position) return 1;
    // ELSE, criteria one is the same for both - we need to look at criteria two:
    if($a_details->crit_two_position < $b_details->crit_two_position) return -1;
    if($a_details->crit_two_position > $b_details->crit_two_position) return 1;
    // ELSE both criteria are the same (same font?)
    return 0;
});

print_r($fonts); // should be sorted!

, !

0

This question listened to me all night, so I came up with another option. This is a universal and reusable solution that will work by any criteria. (At least anyone that I can think of.) Here you can find.

<?php

/**
 *  Sorts an array based on matching multiple criteria.
 *
 *  Given:
 *  $array => ['big cat', 'small dog', 'big dog', 'small cat']
 *  $criteria => [['dog','cat'], ['big','small']]
 *
 *  Result: (biggest to smallest)
 *  ['big dog', 'small dog', 'big cat', 'small cat'] 
 */
function multi_sort(&$array, $criteria, $defaults=array()){
    $cache = array();

    // prepare the criteria by sorting them from longest to shortest 
    // maintaining the original key (index)
    foreach($criteria as &$c){
        uasort($c, function($a,$b){
            return  strlen($b) - strlen($a);
        });
    }

    // define a function for returning the index matching the given str
    // given: 'one' and ['zero', 'one', 'two'] returns 1
    $findIndex = function($str, $values){
        foreach($values as $index=>$value){
            if( stripos($str, $value) !== FALSE ){
                return $index;
            }
        }
        return NULL;
    };

    // define a function to calculate a weighted value based on the criteria
    // returns a value similar to: 2000-0000-3300 (one segment for each criteria)
    $calculateValue = function($str) use ($criteria, $findIndex, $defaults, $cache){
        if( !isset($cache[$str]) ){
            $parts = array();
            foreach($criteria as $i=>$c){
                $parts[$i] = $findIndex($str, $c);
                if( $parts[$i] === NULL ){
                    $parts[$i] = (isset($defaults[$i]) ? $defaults[$i] : 1000);
                }
                $parts[$i] = str_pad($parts[$i], 4, '0');
            }
            $cache[$str] = implode($parts, '-');
        }
        return $cache[$str];
    };

    // define our compare function
    $compare = function($a, $b) use ($calculateValue){
        $av = $calculateValue($a);
        $bv = $calculateValue($b);
        return $av > $bv;
    };

    // sort the array`
    usort($array, $compare);
}

$list = array(
    'Bold', 'ExtraBold', 'ExtraLight', 'Light', 'Medium', 'Regular', 'SemiBold', 'Thin', 'Condensed Bold', 'Expanded Black', 'Condensed ExtraLight', 'Expanded Thin'
);

// create our sort criteria.
$sort_criteria = array(
    array("Expanded", "Standard", "Condensed"),
    array("Black", "ExtraBold", "Bold", "SemiBold", "Medium", "Regular", "Light", "Thin", "ExtraLight")
);
// sort our array; default for criteria 1 is 1 (i.e. Standard)
multi_sort($list, $sort_criteria, array(1));
print_r($list);

// lets sort some animals from biggest to smallest.
$animals = ['big cat', 'small dog', 'big dog', 'small cat'];
$sort_criteria = [['dog','cat'], ['big','small']];
multi_sort($animals, $sort_criteria);
print_r($animals);
0
source

Source: https://habr.com/ru/post/1666553/


All Articles