根据php中元素的最后和第一个字符匹配排列数组元素

Given a string of word arrange them in such an order that there exist words like X -> Y -> Z in such a way that last char of X is first char of Y and last char of Y is first char of Z.

For example :

"sam let mat xaml tax"

will become

"sam mat tax xaml let"

My version of this algorithm rearranges the words, but: - does not include those words that cannot form the chain of words (the chain of words is started by the word that finds one coincidence at least) - does not restart another chain with the rest of words that didn't coincide with the first chain of words. That is to say, there is only 1 chain of words

That is to say that:

"ysamz let mat xaml gallery tax"

would give:

let tax xaml

this happens because it does not find any coincidence for ysamz, gallery and mat.

http://sandbox.onlinephpfunctions.com/code/7f911e410510980331627832889816997abe24db

 function right($string,$chars) 
 { 
  $vright = substr($string, strlen($string)-$chars,$chars); 
  return $vright; 
} 
function left($string,$chars){ 
    $vleft=substr($string, 0,$chars);
    return $vleft;
} 
function findone($str,&$strArray,$currentword)
{
  $chosen="";
  foreach ($strArray as $i => $strinarray) 
  {
      if(left($strinarray,1)==$str)
      {
          $chosen=$strinarray;
          unset($strArray[$i]);
          break;
      }
  }
  return $chosen;
}
function findonepattern($str,&$strArray,$currentword)
{
   $chosen="";
    $coincidences=preg_grep('/^'.$str.'.*$/', $strArray);
    if(sizeof($coincidences)>0)
  {
     $chosen=current($coincidences);
     $delWord=array_keys($strArray, $chosen);
      unset($strArray[$delWord[0]]);
      $strArray=array_values($strArray);

    }

 return $chosen;

}


function rearrange($lastvalue,&$strArray)
{
    global $finalArray,$globalcount;
    $last=right($lastvalue, 1);
  // $chosen=findonepattern($last,$strArray,$lastvalue);
 $chosen=findone($last,$strArray,$lastvalue);
    if(!empty($chosen))
    {
    //this line is commented because if there is more than one similar word
          //it would not consider the second one
          //  if(!in_array($chosen, $finalArray)) $finalArray[]=$chosen; 
        $finalArray[]=$chosen;   

       rearrange($chosen, $strArray);
   }
 if(sizeof($finalArray)==1 && $globalcount<sizeof($strArray)) 
  {
    $globalcount++;
    $finalArray[0]=$strArray[$globalcount];
     rearrange($finalArray[0], $strArray);
  }
    return $finalArray;
}
$globalcount=0;
    $thestring="sam let mat xaml tax";
    $strArray=explode(" ",$thestring);
    $strArray=array_filter($strArray);
    $finalArray=array();
    $finalArray[]=$strArray[0];
    unset($strArray[0]);
    $finalArray=rearrange($finalArray[0],$strArray);
    foreach($finalArray as $finalstr)
    {
     echo $finalstr." ";
    }

PREG PATTERN Instead of using the findone function that makes use of "left", you could use a pattern but there is a worse performance:

function findonepattern($str,&$strArray,$currentword)
{
   $chosen="";
    $coincidences=preg_grep('/^'.$str.'.*$/', $strArray);
    if(sizeof($coincidences)>0)
  {
     $chosen=current($coincidences);
     $delWord=array_keys($strArray, $chosen);
      unset($strArray[$delWord[0]]);
      $strArray=array_values($strArray);

    }

 return $chosen;

}

You can see the performance with 3000 words here:

http://sandbox.onlinephpfunctions.com/code/5ae84a2dadc8140eeb1e776d74059a204877bf0a

First solution: aprox. 0.3 seconds Second solution (preg): aprox 1 second

try recursion function:

<?php
$myStr = "sam let mat xaml tax";
var_dump($myStr);

$myStr = explode(' ', $myStr);
$finalArr = find($myStr[0], $myStr, array(), array());
$finalArr = array_unique($finalArr);

$strFinal = implode(" ", $finalArr);
var_dump($strFinal);

function find($currentWord, $myStr, $OUTPUT = array(), $unic = array()){
    $indexWord = array_search($currentWord, $myStr);
    $findFlag = false;
    foreach($myStr as $keyInLoop=>$wordInLoop){
        if(substr($currentWord, -1) == $wordInLoop[0]){
            $findFlag = true;
            $OUTPUT[] = $currentWord;
            $OUTPUT[] = $wordInLoop;
            unset($myStr[$indexWord]);
            $myStr = array_values($myStr);

            if(!count($myStr)) return array_merge($OUTPUT, $unic);
            elseif(count($myStr) == 1) {$unic[count($OUTPUT)+count($unic)+1] = $myStr[0]; return array_merge($OUTPUT, $unic);}
            else return find($wordInLoop, $myStr, $OUTPUT, $unic);
        }
    }
    if(!$findFlag){
        $unic[count($OUTPUT)+count($unic)+1] = $currentWord;
        unset($myStr[$indexWord]);
        $myStr = array_values($myStr);
        if(!count($myStr)) return array_merge($OUTPUT, $unic);
        elseif(count($myStr) == 1) {$unic[count($OUTPUT)+count($unic)+1] = $myStr[0]; return array_merge($OUTPUT, $unic);}
        else return find($myStr[0], $myStr, $OUTPUT, $unic);
    }
}
?>