排列组合很常见的算法,但是这是第一次从元素中删除全部可能性元素再进行排列这样计算,得记录记录。。。。
比如 数组有1,2两个元素,排列组合为[1,2],[2,1],[1],[2]
但是得注意一下,如果数组元素过多可能会内存溢出
<?php
class KeywordLogic
{
/**
* 获取新的字符串
* @param string $word
* @param $pubProductId
* @param $siteLangId
* @return string
*/
public function getShuffle(string $word,$pubProductId,$siteLangId): string
{
Log::getInstance()->info(__CLASS__.'@'.__FUNCTION__."开始处理",['args'=>func_get_args()]);
$historyArray = KeywordShuffleCache::get($pubProductId,$siteLangId);
$historyArray[] = $word;
KeywordShuffleCache::storage($pubProductId,$siteLangId,$word);
$newWord = $this->generateNewString($word,$historyArray);
KeywordShuffleCache::storage($pubProductId,$siteLangId,$newWord);
return $newWord;
}
/**
* 生成新的字符串
* @param $inputString
* @param $historyArray
* @return string
*/
private function generateNewString($inputString, $historyArray): string
{
// 将输入字符串转换为字符数组
if(strpos($inputString,PHP_EOL)!==false){
$strList = array_values(array_filter(explode(PHP_EOL,$inputString)));
$fuhao = PHP_EOL;
}else{
$strList = array_values(array_filter(explode(" ",$inputString)));
$fuhao = " ";
}
$permutations = $this->getAllPermutations($strList);
// 遍历所有排列,查找不在历史数组中的字符串
foreach ($permutations as $permutation) {
$newString = implode($fuhao, $permutation);
if (!in_array($newString, $historyArray)) {
// 如果找到新字符串,返回它
Log::getInstance()->info(__CLASS__.'@'.__FUNCTION__."找到了未使用过的组合字符串",['args'=>func_get_args(),'result'=>$newString]);
return $newString;
}
}
// 如果没有找到新字符串,随便返回一个
$randomIndex = rand(0,count($strList)-1);
$newString = implode($fuhao,$permutations[$randomIndex]);
Log::getInstance()->info(__CLASS__.'@'.__FUNCTION__."全部使用过,随机返回1个",['args'=>func_get_args(),'result'=>$newString,"permutations"=>$permutations,'randomIndex'=>$randomIndex]);
return $newString;
}
/**
* 获取全部元素及全部减少后元素的排列组合
* @param array $arr
* @return array|array[]
*/
private function getAllPermutations(array $arr): array
{
$permutations = $this->getPermutations($arr);
$maxReducedNum = count($arr)-1;
if($maxReducedNum){
for($reducedNum=1;$reducedNum<=$maxReducedNum;$reducedNum++){
//减哪几个元素呢
$diffCombinationList = $this->getCombinations($arr,$reducedNum);
foreach($diffCombinationList as $diffItemList){
$reducedArr = array_diff($arr,$diffItemList);
$permutations = array_merge($permutations,$this->getPermutations($reducedArr));
}
}
}
return $permutations;
}
/**
* 根据数组元素生成全部排列组合值
* @param $items
* @param array $perms
* @return array|array[]
*/
private function getPermutations($items, $perms = array()): array
{
if (empty($items)) {
return array($perms);
} else {
$return = array();
for ($i = count($items) - 1; $i >= 0; --$i) {
$newItems = $items;
$newPerms = $perms;
list($foo) = array_splice($newItems, $i, 1);
array_unshift($newPerms, $foo);
$return = array_merge($return, $this->getPermutations($newItems, $newPerms));
}
return $return;
}
}
/**
* 从数组中挑出指定个数的元素的全部可能的组合
* @param $base
* @param $n
* @return array|array[]
*/
private function getCombinations($base, $n): array
{
$baseLen = count($base);
if ($n == 0) {
return array(array());
} else {
$result = array();
for ($i = 0; $i <= $baseLen - $n; $i++) {
$temp1 = $base[$i];
$temp2 = array_slice($base, $i + 1);
foreach ($this->getCombinations($temp2, $n - 1) as $subCombo) {
array_unshift($subCombo, $temp1);
$result[] = $subCombo;
}
}
return $result;
}
}
}
测试执行结果
$result = (new KeywordLogic())->getShuffle("hello word",123,'jp');