我有一个这样的数组:
['ball', 'football', 'volleyball', 'football player', 'football league', 'tennis']
我想根据“football”关键字对其进行排序:
['football', 'football player', 'football league', 'ball', 'volleyball', 'tennis']
我怎样才能做到这一点?
答案 0 :(得分:4)
您需要制作自定义排序功能,然后将其与usort.
$array=["ball","football","volleyball","football player","football league","tennis"];
function footsort($a,$b) {
$afoot=substr($a,0,8)=="football";
$bfoot=substr($b,0,8)=="football";
if ($afoot==$bfoot) return strcmp($a,$b);
/*else*/
if ($afoot) return -1;
if ($bfoot) return 1;
}
usort($array,"footsort");
print_r($array);
响应:
Array
(
[0] => football
[1] => football league
[2] => football player
[3] => ball
[4] => tennis
[5] => volleyball
)
答案 1 :(得分:1)
如果您想根据关键字是否在单词中的任何位置而不是在开头找到排序,您可以在比较函数中使用strpos
。
$keyword = 'football';
usort($things, function($a, $b) use ($keyword) {
$x = strpos($a, $keyword) === false;
$y = strpos($b, $keyword) === false;
if ($x && !$y) return 1;
if ($y && !$x) return -1;
// use this if you want to sort alphabetically after the keyword sort:
return strcmp($a, $b);
// or if you only want to sort by whether or not the keyword was found:
return 0;
});
如果您有更一般的目标,即根据" closeness"对数组进行排序。它的术语与关键词的比较必须变得更加复杂,它应该做的方式实际上取决于"亲密度"对你来说最重要。这是一个更复杂的排序的例子,可能不是你想要的,但只是为了表明我对确定"亲密度"的可能复杂性的意思:
$keyword = 'football';
usort($things, function($a, $b) use ($keyword) {
// prioritize exact matches first
if ($a == $keyword) return -1;
if ($b == $keyword) return 1;
// prioritize terms containing the keyword next
$x = strpos($a, $keyword);
$y = strpos($b, $keyword);
if ($x !== false && $y === false) return -1;
if ($y !== false && $x === false) return 1;
if ($x !== false && $y !== false) { // both terms contain the keyword, so...
if ($x != $y) { // prioritize matches closer to the beginning of the term
return $x > $y ? 1 : -1;
}
// both terms contain the keyword at the same position, so...
$al = strlen($a);
$bl = strlen($b);
if ($al != $bl) { // prioritize terms with fewer characters other than the keyword
return $al > $bl ? 1 : -1;
}
// both terms contain the same number of additional characters
return 0;
// or sort alphabetically with strcmp($a, $b);
// or do additional checks...
}
// neither terms contain the keyword
// check the character similarity...
$ac = levenshtein($keyword, $a);
$bc = levenshtein($keyword, $b);
if ($ac != $bc) {
return $ac > $bc ? 1 : -1;
}
return 0;
// or sort alphabetically with strcmp($a, $b);
// or do additional checks, similar_text, etc.
});
答案 2 :(得分:1)
我试图理解你的问题,并尝试像这样解决
<?php
$abc =["ball","football","volleyball","football player", "football league", "tennis"];
$word ="football";
$final = array();
// collect complete match
foreach($abc as $key=>$value){
if($value==$word){
$final[] = $value;
unset($abc[$key]);
}
}
//collect if word found in another string
foreach($abc as $key=>$value){
if(strpos($value,$word)!==false){
$final[] = $value;
unset($abc[$key]);
}
}
// collect if another string have some part of word
foreach($abc as $key=>$value){
if(strpos($word,$value)!==false){
$final[] = $value;
unset($abc[$key]);
}
}
// collect rest of the elements
$final = array_merge($final,$abc);
print_r($final);
?>
输出
Array
(
[0] => football
[1] => football player
[2] => football league
[3] => ball
[4] => volleyball
[5] => tennis
)
答案 3 :(得分:0)
这是一个有趣的小问题,你需要为大海捞针的每个元素(单词数组)分配某种分数。我认为对每个元素进行评分的最佳方法是基于经典的动态编程问题“最长公共子字符串”。该子字符串越长,排序分数越高。
//find the longest commson substring between 2 strings, return all substrings of that length
function longestCommonSubstring($string1, $string2) {
$helper = array();
//create two dimensional array, to keep track
for($i =0; $i < strlen($string1); $i++) {
$helper[$i] = array();
for($j=0; $j< strlen($string2); $j++) {
//intialize all values to 0
$helper[$i][] = 0;
}
}
$max= 0;
$ans = array();
for($i =0; $i <strlen($string1); $i++) {
for($j =0; $j < strlen($string2); $j++) {
if ($string1[$i] == $string2[$j]) {
if($i==0 || $j==0) {
$helper[$i][$j] = 1;
} else {
$helper[$i][$j] = $helper[$i-1][$j-1] + 1;
}
if ($helper[$i][$j] > $max) {
$max = $helper[$i][$j];
$ans = array(substr($string1, $i-$max+1, $max));
} elseif($helper[$i][$j] == $max) {
$ans[] = substr($string1, $i-$max+1, $max);
}
} else {
$helper[$i][$j] = 0;
}
}
}
return $ans;
}
现在编写了函数,我们需要使用它。
foreach($words as $word) {
$lcs = longestCommonSubstring($keyword, $word);
}
嗯,这一切都很好,但只使用这个功能只是成功的一半,现在我们需要对结果应用一些逻辑。让我们将结果保存在一个数组中,并给每个单词一个分数。得分最好的是最长子串的长度。 football
比ball
更好,因为它有一个更长的字符串。但是football
和football player
怎么样,它们都具有相同长度的最长公共子串?为了解决这个问题,我们可以使用长度作为总字长的百分比。结合这两个想法,最长的子串长度和百分比,我们得到下面的代码。
//an associative array to save the scores
// $wordsMeta[$word] = array(lengthOfCommonSubstring, percentageOfWordMatched)
$wordsMeta = array();
//go through each word and assign a score
foreach($words as $word) {
$lcs = longestCommonSubstring($keyword, $word);
if (count($lcs) ==0 ) {
$wordPercentage = 0;
$wordLength = 0;
} else {
$wordLength = strlen($lcs[0]);
$wordPercentage = $wordLength/strlen($word);
}
$wordsMeta[$word] = array(
"percentageOfWordMatched" => $wordPercentage,
"lengthOfCommonSubstring" => $wordLength
);
}
现在我们只需要一个首先查看长度的排序函数,如果它们相等,它将查看百分比并返回一个合适的整数。
//our special sorting function
//checks length, if that is equal, then it checks percentage of word matched
//if both are eqaul, then those two elements are considered equal
$sort = function($a, $b) {
$ans = $a["lengthOfCommonSubstring"] - $b["lengthOfCommonSubstring"];
if ($ans == 0) {
$ans = $a["percentageOfWordMatched"] - $b["percentageOfWordMatched"];
}
if ($ans < 0) {
$ans = -1;
} elseif ($ans > 0){
$ans = 1;
} else {
$ans = 0;
}
//higher number = lower sort order
$ans *= -1;
return $ans;
};
现在简单的部分:uasort($wordsMeta)
和$answer= array_keys($wordsMeta)
小心恶魔 - 这个算法很慢。非常慢。 lcs
为O(n*m)
,我们称之为count($words)
次。将评分过程O(n*m*x)
放在:
n
是strlen($keyword)
m
是strlen($word)
x
是count($words)
此外,我们正在排序,即O(n * log(n))
。所以总的来说这个算法是O(n*m*x + n*log(n))
并不好。保持单词列表简短,单词列表中的单词缩短,关键字short将保持速度下降。