我有像这样的PHP数组
$array = array("foo", "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo", "w44orld");
我想将数组的每个元素与剩余元素进行比较。
例如:我想要完成"foo" with "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo" and "w44orld"
。
然后,我想要压缩"bar" with "foo", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "foo", "bard", "hzallo", "w44orld"
等等,直到最后一个元素。
让我们考虑元素,我们将其作为$var_1
进行比较,将剩余元素的变量视为$ var_2;
如果similar_text($var_1, $var_2, $percent);
返回$percent value > 90%
,那么我想要打印
$var_1
以及匹配百分比>的$var_2
的所有相应类似文字值90
目前我计划使用两个循环实现此目的,$var_1
的外部循环和$var_2
的内部循环。
array
的每个元素最多可以包含5000个字符,并且数组中可以有1000个元素,因此我当前的逻辑非常昂贵。
以更好的方式处理它的任何方向?
答案 0 :(得分:3)
为了使索引工作,数组$arr
必须具有唯一值:
$arr = array("foo", "bar", "hallo", "world", "fooo", "bar1", "hall_o", "wor1ld", "bard", "hzallo", "w44orld");
$dexed = array();
foreach ($arr as $key => $value){
$dexed[$key]['val'] = $value;
$dexed[$key]['key'] = $key;
}
$out = array();//output
$rev = array();//reverse lookup array
$t = 80;//threshold value
$cnt = count($dexed);
$k = 0;
for ($i=0; $i<$cnt-1; $i++){
for ($j=$i+1; $j<$cnt; $j++){
//similar_text calculates differently depending on order of arguments
similar_text($dexed[$i]['val'], $dexed[$j]['val'], $percent1);
similar_text($dexed[$j]['val'], $dexed[$i]['val'], $percent2);
if (($percent1 >= $t) || ($percent2 >= $t)){
//check if value already exists under different key
if (in_array($dexed[$i]['val'], array_keys($rev))){
if ( ! in_array($dexed[$j]['val'], array_keys($rev))){
$fkey = $rev[$dexed[$i]['val']];//key found
$next = count($out[$fkey]);
$out[$fkey][$next]['val'] = $dexed[$j]['val'];
$out[$fkey][$next]['key'] = $dexed[$j]['key'];
$rev[$dexed[$j]['val']] = $fkey;
}
} else {
$out[$k][0]['val'] = $dexed[$i]['val'];
$out[$k][0]['key'] = $dexed[$i]['key'];
$out[$k][1]['val'] = $dexed[$j]['val'];
$out[$k][1]['key'] = $dexed[$j]['key'];
$rev[$dexed[$i]['val']] = $k;
$rev[$dexed[$j]['val']] = $k;
$k++;
}
}
}
}
生成$out
后,使用以下命令生成索引数组:
$index = array();
foreach ($out as $key => $group){
$cnt = count($group);
foreach ($group as $key2 => $word){
for ($i=0; $i<$cnt; $i++){
if ($i != $key2){
$index[$word['key']][] = $key.':'.$i;
}
}
}
}
访问给定键的所有相似字词(原始数组$arr
中字词的键值);
$key = 2;
foreach ($index[$key] as $value){
$parts = explode(':', $value);
echo '<p>'.$out[$parts[0]][$parts[1]]['val'].'</p>';
}
答案 1 :(得分:2)
不幸的是,如果列表变得比琐碎的更大并且不能很好地工作,那么你所建议的是缓慢的。这可能是,而且在算法上也是有效的。
首先,创建一个字母bigrams(http://en.wikipedia.org/wiki/Bigram)的倒排索引。例如(假设不区分大小写):
您可以使用下划线而不是^和$,它们是伪字符。我认为他们会帮助你对结果进行排名。
现在要找到相似的单词,您可以使用典型的排名算法(请参阅tf * idf和更简单的基于令牌计数的算法)来对最佳匹配进行排名。所以,给“hallo”,
QUERY(^ h,ha,al,ll,lo,o $)AGAINST index_of_words
&安培;你会得到一个很好的匹配“hzallo”因为^ h,al,ll,lo,o $都匹配。
你需要像Solr或你的数据库的TEXT索引这样做,除非你想写一个简单的倒排索引,但它是值得的。查找速度将比您的娱乐速度快几个数量级,并且结果将按接近程度进行排名。
之后,你可以使用像levenshtein这样的东西,但在很多情况下我认为你不需要。