按任意数量的子字符串对字符串数组进行排序 [英] Sorting an array of strings by arbitrary numbers of substrings
问题描述
我正在尝试修改
我已经在 uasort
上待了一段时间(必须保持键关联),并且已经接近了.诚然,这是由于绝望的结果而不是任何严格的方法所造成的.不太了解 uasort
的工作方式在某种程度上限制了我.
//获得列表中名称空间组件的最大数量$ ns_counts = array_map(function($ val){返回计数(explode(爆炸"("\"",$ val ["namespace"))));},$ indexes);$ limit = max($ ns_counts);for($ depth = 0; $ depth< = $ limit; $ depth ++){uasort($ indexes,function($ first,$ second)use($ depth,$ limit){$ fexp = explode("\\",$ first [命名空间"]);$ sexp = explode("\\",$ second ["namespace"]);如果($ depth === $ limit){//为什么有帮助?array_pop($ fexp);array_pop($ sexp);}$ fexp = array_slice($ fexp,0,$ depth + 1,true);$ sexp = array_slice($ sexp,0,$ depth + 1,true);$ fimp = implode(",$ fexp);$ simp = implode(",$ sexp);//回显"$ depth:$ fimp<->$ simp \ n";返回strnatcmp($ fimp,$ simp);});}回声json_encode($ indexes,JSON_PRETTY_PRINT);
这给了我正确排序的输出,但是在底部而不是顶部有更深的名称空间:
<代码> {"31":{名称空间":"M";},"12":{名称空间":"A \\ Bees"},"16":{名称空间":"A \\ Sea"},"3":{名称空间":"A \\ B \\ Bee"},"9":{名称空间":"A \\ B \\ See"},"38":{名称空间":"A \\ B \\ C \\ Dee"},"51":{" namespace":" X \\ Wye"},"26":{名称空间":"X \\ Y \\ Zed"}}
我想我可能必须为每个级别的命名空间构建一个单独的数组并对其进行单独排序,但是在如何做到这一点上有一个空白.有什么建议可以完成这项工作的最后一步,或者有什么完全不同但又不涉及太多循环的事情?
我认为以下方法应该有效:
uasort($ indexes,静态函数(数组$ entry1,数组$ entry2):int {$ ns1Parts = explode('\\',$ entry1 ['namespace']);$ ns2Parts = explode('\\',$ entry2 ['namespace']);$ ns1Length = count($ ns1Parts);$ ns2Length = count($ ns2Parts);for($ i = 0; $ i< $ ns1Length& isset($ ns2Parts [$ i]); $ i ++){$ isLastPartForNs1 = $ i === $ ns1Length-1;$ isLastPartForNs2 = $ i === $ ns2Length-1;如果($ isLastPartForNs1!== $ isLastPartForNs2){返回$ isLastPartForNs1< =>$ isLastPartForNs2;}$ nsComparison = $ ns1Parts [$ i]< =>$ ns2Parts [$ i];如果($ nsComparison!== 0){返回$ nsComparison;}}返回0;});
它的作用是:
- 将名称空间拆分为多个部分,
- 比较从第一个部分开始的每个部分,然后:
- 如果我们只讨论最后一部分而不是另一部分,则优先考虑具有最多部分的那一部分,
- 否则,如果各自的部分不同,则按字母顺序优先于另一部分.
I'm attempting to modify the OrderedImportsFixer
class in php-cs-fixer so I can clean up my files the way I want. What I want is to order my imports in a fashion similar to what you'd see in a filesystem listing, with "directories" listed before "files".
So, given this array:
$indexes = [
26 => ["namespace" => "X\\Y\\Zed"],
9 => ["namespace" => "A\\B\\See"],
3 => ["namespace" => "A\\B\\Bee"],
38 => ["namespace" => "A\\B\\C\\Dee"],
51 => ["namespace" => "X\\Wye"],
16 => ["namespace" => "A\\Sea"],
12 => ["namespace" => "A\\Bees"],
31 => ["namespace" => "M"],
];
I'd like this output:
$sorted = [
38 => ["namespace" => "A\\B\\C\\Dee"],
3 => ["namespace" => "A\\B\\Bee"],
9 => ["namespace" => "A\\B\\See"],
12 => ["namespace" => "A\\Bees"],
16 => ["namespace" => "A\\Sea"],
26 => ["namespace" => "X\\Y\\Zed"],
51 => ["namespace" => "X\\Wye"],
31 => ["namespace" => "M"],
];
As in a typical filesystem listing:
I've been going at uasort
for a while (key association must be maintained) and have come close. Admittedly, this is due more to desperate flailing than any sort of rigorous methodology. Not really having a sense of how uasort
works is kind of limiting me here.
// get the maximum number of namespace components in the list
$ns_counts = array_map(function($val){
return count(explode("\\", $val["namespace"]));
}, $indexes);
$limit = max($ns_counts);
for ($depth = 0; $depth <= $limit; $depth++) {
uasort($indexes, function($first, $second) use ($depth, $limit) {
$fexp = explode("\\", $first["namespace"]);
$sexp = explode("\\", $second["namespace"]);
if ($depth === $limit) {
// why does this help?
array_pop($fexp);
array_pop($sexp);
}
$fexp = array_slice($fexp, 0, $depth + 1, true);
$sexp = array_slice($sexp, 0, $depth + 1, true);
$fimp = implode(" ", $fexp);
$simp = implode(" ", $sexp);
//echo "$depth: $fimp <-> $simp\n";
return strnatcmp($fimp, $simp);
});
}
echo json_encode($indexes, JSON_PRETTY_PRINT);
This gives me properly sorted output, but with deeper namespaces on the bottom instead of the top:
{
"31": {
"namespace": "M"
},
"12": {
"namespace": "A\\Bees"
},
"16": {
"namespace": "A\\Sea"
},
"3": {
"namespace": "A\\B\\Bee"
},
"9": {
"namespace": "A\\B\\See"
},
"38": {
"namespace": "A\\B\\C\\Dee"
},
"51": {
"namespace": "X\\Wye"
},
"26": {
"namespace": "X\\Y\\Zed"
}
}
I'm thinking I may have to build a separate array for each level of namespace and sort it separately, but have drawn a blank on how I might do that. Any suggestions for getting the last step of this working, or something completely different that doesn't involve so many loops?
I believe the following should work:
uasort($indexes, static function (array $entry1, array $entry2): int {
$ns1Parts = explode('\\', $entry1['namespace']);
$ns2Parts = explode('\\', $entry2['namespace']);
$ns1Length = count($ns1Parts);
$ns2Length = count($ns2Parts);
for ($i = 0; $i < $ns1Length && isset($ns2Parts[$i]); $i++) {
$isLastPartForNs1 = $i === $ns1Length - 1;
$isLastPartForNs2 = $i === $ns2Length - 1;
if ($isLastPartForNs1 !== $isLastPartForNs2) {
return $isLastPartForNs1 <=> $isLastPartForNs2;
}
$nsComparison = $ns1Parts[$i] <=> $ns2Parts[$i];
if ($nsComparison !== 0) {
return $nsComparison;
}
}
return 0;
});
What it does is:
- split namespaces into parts,
- compare each part starting from the first one, and:
- if we're at the last part for one and not the other, prioritize the one with the most parts,
- otherwise, if the respective parts are different, prioritize the one that is before the other one alphabetically.
这篇关于按任意数量的子字符串对字符串数组进行排序的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!