我有一系列字体名称,就宽度而言,然后就重量而言(按字母顺序排列)。标准 width 在字符串中没有像其他宽度那样的指示符(压缩,扩展等)。这是我得到它时阵列的样子:
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)
我需要先根据此宽度顺序对其进行排序:
$order_array_crit_one = array("Expanded", "Standard", "Condensed");
然后根据这个顺序的重量:
$order_array_crit_two = array("Black", "ExtraBold", "Bold", "SemiBold", "Medium", "Regular", "Light", "Thin", "ExtraLight");
我使用比较单词(like this)的排序函数来解决这个问题,但到目前为止我提出的每个解决方案都是庞大而混乱的。
答案 0 :(得分:1)
过于复杂的比较问题在于它使得usort效率不高,因为它必须多次转换和评估项目。但是,如果以前使用基本排序方式转换数组,则可以减少此工作。一个想法是重建数组,但这次使用计算的数字键:
// 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 :(得分:0)
为什么不创建一个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
}
答案 2 :(得分:0)
假设" Bold"与"标准粗体"相同,并且您无法按照其他答案中的建议更改输入数组,这样可行:
$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!
希望这有帮助!
答案 3 :(得分:0)
这个问题一直困扰着我,所以我提出了另一种选择。这是一个通用且可重复使用的解决方案,适用于任何标准。 (至少我能想到的任何一个。)你可以找到demo here。
<?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);