Warning: file_get_contents(/data/phpspider/zhask/data//catemap/1/php/266.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181

Warning: file_get_contents(/data/phpspider/zhask/data//catemap/4/algorithm/12.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Php 查找字符串数组的公共前缀_Php_Algorithm_String - Fatal编程技术网

Php 查找字符串数组的公共前缀

Php 查找字符串数组的公共前缀,php,algorithm,string,Php,Algorithm,String,我有这样一个数组: $sports = array( 'Softball - Counties', 'Softball - Eastern', 'Softball - North Harbour', 'Softball - South', 'Softball - Western' ); 我想找到字符串的最长公共前缀。在这种情况下,它将是“垒球-” 我想我会遵循这个过程 $i = 1; // loop to the length of the first string while ($i &l

我有这样一个数组:

$sports = array(
'Softball - Counties',
'Softball - Eastern',
'Softball - North Harbour',
'Softball - South',
'Softball - Western'
);
我想找到字符串的最长公共前缀。在这种情况下,它将是
“垒球-”

我想我会遵循这个过程

$i = 1;

// loop to the length of the first string
while ($i < strlen($sports[0]) {

  // grab the left most part up to i in length
  $match = substr($sports[0], 0, $i);

  // loop through all the values in array, and compare if they match
  foreach ($sports as $sport) {

     if ($match != substr($sport, 0, $i) {
         // didn't match, return the part that did match
         return substr($sport, 0, $i-1);
     }

  } // foreach

   // increase string length
   $i++;
} // while

// if you got to here, then all of them must be identical
$i=1;
//循环到第一个字符串的长度
而($i
问题

  • 是否有内置函数或更简单的方法来实现这一点

  • 对于我的5行数组,这可能很好,但是如果我要做几千行数组,会有很多开销,所以我必须用
    $I
    的起始值进行移动计算,例如
    $I
    =字符串的一半,如果失败,则
    $I/2
    直到它工作,然后将
    $I
    增加1直到我们成功了,所以我们做了最少的比较来得到结果


  • 对于这类问题,已经有了一个公式/算法了吗?

    可能有一些非常受欢迎的算法,但我不知道,如果你知道你的共性会像你的例子中那样出现在左边,你可以先找到前两个字符串的公共性,然后遍历列表的其余部分,根据需要修剪公共字符串以实现公共性,如果一直修剪到零,则以失败告终

  • 据我所知,没有

  • 是:不必比较从0到长度i的子字符串,只需检查第i个字符(您已经知道字符0到i-1匹配)


  • 我认为您的方法是正确的。但是当所有字符串都通过时,您可以这样做,而不是增加I:

    1) 比较数组中的前两个字符串,找出它们有多少个常用字符。例如,将常用字符保存在名为maxCommon的单独字符串中

    2) 比较第三个字符串w/maxCommon。如果常用字符数较小,请将maxCommon修剪为匹配的字符

    3) 对阵列的其余部分重复并冲洗。在该过程结束时,maxCommon将拥有所有数组元素共有的字符串

    这会增加一些开销,因为您需要比较每个字符串w/maxCommon,但会大大减少获得结果所需的迭代次数

    我假设“公共部分”是指“最长的公共前缀”。这是一个比任何普通子字符串都要简单得多的计算方法

    如果在最坏的情况下不读取
    (n+1)*m
    字符,在最好的情况下不读取
    n*m+1
    ,则无法执行此操作,其中
    n
    是最长公共前缀的长度,
    m
    是字符串数

    一次比较一个字母就可以达到这种效率(大θ(n*m))

    您提出的算法以大θ(n^2*m)运行,这对于大输入来说要慢得多

    第三种算法是查找前两个字符串的最长前缀,然后将其与第三个、第四个等进行比较。该算法的运行时间也为大θ(n*m),但常数因子较高。在实践中可能只会稍微慢一点

    总的来说,我建议您只运行自己的函数,因为第一个算法太慢,而另外两个算法编写起来也同样复杂

    查看大θ符号的描述。

    我会使用以下方法:

    $prefix = array_shift($array);  // take the first item as initial prefix
    $length = strlen($prefix);
    // compare the current prefix with the prefix of the same length of the other items
    foreach ($array as $item) {
        // check if there is a match; if not, decrease the prefix by one character at a time
        while ($length && substr($item, 0, $length) !== $prefix) {
            $length--;
            $prefix = substr($prefix, 0, -1);
        }
        if (!$length) {
            break;
        }
    }
    

    更新 下面是另一个解决方案,迭代比较字符串的每个第n个字符,直到发现不匹配:

    $pl = 0; // common prefix length
    $n = count($array);
    $l = strlen($array[0]);
    while ($pl < $l) {
        $c = $array[0][$pl];
        for ($i=1; $i<$n; $i++) {
            if ($array[$i][$pl] !== $c) break 2;
        }
        $pl++;
    }
    $prefix = substr($array[0], 0, $pl);
    
    $pl=0;//公共前缀长度
    $n=计数($array);
    $l=strlen($array[0]);
    而($pl<$l){
    $c=$array[0][$pl];
    
    对于($i=1;$i@bumperbox

  • 您的基本代码需要进行一些修改才能在所有场景中正常工作

    • 循环仅在最后一个字符之前比较一个字符
    • 不匹配可能发生在最新公共字符之后的1个循环周期
    • 因此,您必须至少检查第一个字符串的最后一个字符后的1个字符

    • 因此,您的比较运算符必须是“I将@diogoriba算法实现为代码,结果如下:

      • 找到前两个字符串的公共前缀,然后将其与从第三个开始的所有后续字符串进行比较,如果没有找到公共前缀,则修剪公共字符串,在前缀中的公共前缀多于不同前缀的情况下获胜
      • 但是bumperbox的原始算法(除了错误修复)在字符串前缀中的共同点少于不同的情况下获胜。详细信息请参见代码注释
      我实施的另一个想法是:

      首先检查数组中最短的字符串,并将其用于比较,而不仅仅是第一个字符串

      • 可以显著降低迭代次数,但函数arrayStrLenMin()本身可能会导致(或多或少)迭代次数
      • 简单地从数组中第一个字符串的长度开始似乎很笨拙,但如果arrayStrLenMin()需要多次迭代,可能会很有效
      以尽可能少的迭代次数获取数组中字符串的最大公共前缀(PHP) 代码+广泛测试+备注:

      function shortest($sports) {
       $i = 1;
      
       // loop to the length of the first string
       while ($i < strlen($sports[0])) {
      
        // grab the left most part up to i in length
        // REMARK: Culturally biased towards LTR writing systems. Better say: Grab frombeginning...
        $match = substr($sports[0], 0, $i);
      
        // loop through all the values in array, and compare if they match
        foreach ($sports as $sport) {
         if ($match != substr($sport, 0, $i)) {
          // didn't match, return the part that did match
          return substr($sport, 0, $i-1);
         }
        }
       $i++; // increase string length
       }
      }
      
      function shortestCorrect($sports) {
       $i = 1;
       while ($i <= strlen($sports[0]) + 1) {
        // Grab the string from its beginning with length $i
        $match = substr($sports[0], 0, $i);
        foreach ($sports as $sport) {
         if ($match != substr($sport, 0, $i)) {
          return substr($sport, 0, $i-1);
         }
        }
        $i++;
       }
       // Special case: No mismatch happened until loop end! Thus entire str1 is common prefix!
       return $sports[0];
      }
      
      $sports1 = array(
      'Softball',
      'Softball - Eastern',
      'Softball - North Harbour');
      
      $sports2 = array(
      'Softball - Wester',
      'Softball - Western',
      );
      
      $sports3 = array(
      'Softball - Western',
      'Softball - Western',
      );
      
      $sports4 = array(
      'Softball - Westerner',
      'Softball - Western',
      );
      
      echo("Output of the original function:\n"); // Failure scenarios
      
      var_dump(shortest($sports1)); // NULL rather than the correct 'Softball'
      var_dump(shortest($sports2)); // NULL rather than the correct 'Softball - Wester'
      var_dump(shortest($sports3)); // NULL rather than the correct 'Softball - Western'
      var_dump(shortest($sports4)); // Only works if the second string is at least one character longer!
      
      echo("\nOutput of the corrected function:\n"); // All scenarios work
      var_dump(shortestCorrect($sports1));
      var_dump(shortestCorrect($sports2));
      var_dump(shortestCorrect($sports3));
      var_dump(shortestCorrect($sports4));
      
      function arrayStrLenMin ($arr, $strictMode = false, $forLoop = false) {
          $errArrZeroLength = -1; // Return value for error: Array is empty
          $errOtherType = -2;     // Return value for error: Found other type (than string in array)
          $errStrNone = -3;       // Return value for error: No strings found (in array)
      
          $arrLength = count($arr);
          if ($arrLength <= 0 ) { return $errArrZeroLength; }
          $cur = 0;
      
          foreach ($arr as $key => $val) {
              if (is_string($val)) {
                  $min = strlen($val);
                  $strFirstFound = $key;
                  // echo("Key\tLength / Notification / Error\n");
                  // echo("$key\tFound first string member at key with length: $min!\n");
                  break;
              }
              else if ($strictMode) { return $errOtherType; } // At least 1 type other than string was found.
          }
          if (! isset($min)) { return $errStrNone; } // No string was found in array.
      
          // SpeedRatio of foreach/for is approximately 2/1 as dicussed at:
          // http://juliusbeckmann.de/blog/php-foreach-vs-while-vs-for-the-loop-battle.html
      
          // If $strFirstFound is found within the first 1/SpeedRatio (=0.5) of the array, "foreach" is faster!
      
          if (! $forLoop) {
              foreach ($arr as $key => $val) {
                  if (is_string($val)) {
                      $cur = strlen($val);
                      // echo("$key\t$cur\n");
                      if ($cur == 0) { return $cur; } // 0 is the shortest possible string, so we can abort here.
                      if ($cur < $min) { $min = $cur; }
                  }
              // else { echo("$key\tNo string!\n"); }
              }
          }
      
          // If $strFirstFound is found after the first 1/SpeedRatio (=0.5) of the array, "for" is faster!
      
          else {
              for ($i = $strFirstFound + 1; $i < $arrLength; $i++) {
                  if (is_string($arr[$i])) {
                      $cur = strlen($arr[$i]);
                      // echo("$i\t$cur\n");
                      if ($cur == 0) { return $cur; } // 0 is the shortest possible string, so we can abort here.
                      if ($cur < $min) { $min = $cur; }
                  }
                  // else { echo("$i\tNo string!\n"); }
              }
          }
      
          return $min;
      }
      
      function strCommonPrefixByStr($arr, $strFindShortestFirst = false) {
          $arrLength = count($arr);
          if ($arrLength < 2) { return false; }
      
          // Determine loop length
          /// Find shortest string in array: Can bring down iterations dramatically, but the function arrayStrLenMin() itself can cause ( more or less) iterations.
          if ($strFindShortestFirst) { $end = arrayStrLenMin($arr, true); }
          /// Simply start with length of first string in array: Seems quite clumsy, but may turn out effective, if arrayStrLenMin() needs many iterations.
          else { $end = strlen($arr[0]); }
      
          for ($i = 1; $i <= $end + 1; $i++) {
              // Grab the part from 0 up to $i
              $commonStrMax = substr($arr[0], 0, $i);
              echo("Match: $i\t$commonStrMax\n");
              // Loop through all the values in array, and compare if they match
              foreach ($arr as $key => $str) {
                  echo("  Str: $key\t$str\n");
                  // Didn't match, return the part that did match
                  if ($commonStrMax != substr($str, 0, $i)) {
                          return substr($commonStrMax, 0, $i-1);
                  }
              }
          }
          // Special case: No mismatch (hence no return) happened until loop end!
          return $commonStrMax; // Thus entire first common string is the common prefix!
      }
      
      function strCommonPrefixByChar($arr, $strFindShortestFirst = false) {
          $arrLength = count($arr);
          if ($arrLength < 2) { return false; }
      
          // Determine loop length
          /// Find shortest string in array: Can bring down iterations dramatically, but the function arrayStrLenMin() itself can cause ( more or less) iterations.
          if ($strFindShortestFirst) { $end = arrayStrLenMin($arr, true); }
          /// Simply start with length of first string in array: Seems quite clumsy, but may turn out effective, if arrayStrLenMin() needs many iterations.
          else { $end = strlen($arr[0]); }
      
          for ($i = 0 ; $i <= $end + 1; $i++) {
              // Grab char $i
              $char = substr($arr[0], $i, 1);
              echo("Match: $i\t"); echo(str_pad($char, $i+1, " ", STR_PAD_LEFT)); echo("\n");
              // Loop through all the values in array, and compare if they match
              foreach ($arr as $key => $str) {
                  echo("  Str: $key\t$str\n");
                  // Didn't match, return the part that did match
                  if ($char != $str[$i]) { // Same functionality as ($char != substr($str, $i, 1)). Same efficiency?
                          return substr($arr[0], 0, $i);
                  }
              }
          }
          // Special case: No mismatch (hence no return) happened until loop end!
          return substr($arr[0], 0, $end); // Thus entire first common string is the common prefix!
      }
      
      
      function strCommonPrefixByNeighbour($arr) {
          $arrLength = count($arr);
          if ($arrLength < 2) { return false; }
      
          /// Get the common string prefix of the first 2 strings
          $strCommonMax = strCommonPrefixByChar(array($arr[0], $arr[1]));
          if ($strCommonMax === false) { return false; }
          if ($strCommonMax == "") { return ""; }
          $strCommonMaxLength = strlen($strCommonMax);
      
          /// Now start looping from the 3rd string
          echo("-----\n");
          for ($i = 2; ($i < $arrLength) && ($strCommonMaxLength >= 1); $i++ ) {
              echo("  STR: $i\t{$arr[$i]}\n");
      
              /// Compare the maximum common string with the next neighbour
      
              /*
              //// Compare by char: Method unsuitable!
      
              // Iterate from string end to string beginning
              for ($ii = $strCommonMaxLength - 1; $ii >= 0; $ii--) {
                  echo("Match: $ii\t"); echo(str_pad($arr[$i][$ii], $ii+1, " ", STR_PAD_LEFT)); echo("\n");
                  // If you find the first mismatch from the end, break.
                  if ($arr[$i][$ii] != $strCommonMax[$ii]) {
                      $strCommonMaxLength = $ii - 1; break;
                      // BUT!!! We may falsely assume that the string from the first mismatch until the begining match! This new string neighbour string is completely "unexplored land", there might be differing chars closer to the beginning. This method is not suitable. Better use string comparison than char comparison.
                  }
              }
              */
      
              //// Compare by string
      
              for ($ii = $strCommonMaxLength; $ii > 0; $ii--) {
                  echo("MATCH: $ii\t$strCommonMax\n");
                  if (substr($arr[$i],0,$ii) == $strCommonMax) {
                      break;
                  }
                  else {
                      $strCommonMax = substr($strCommonMax,0,$ii - 1);
                      $strCommonMaxLength--;
                  }
              }
          }
          return substr($arr[0], 0, $strCommonMaxLength);
      }
      
      
      
      
      
      // Tests for finding the common prefix
      
      /// Scenarios
      
      $filesLeastInCommon = array (
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/1",
      "/Vol/2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/2",
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/1",
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/2",
      "/Vol/2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/c/1",
      "/Vol/2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/1",
      );
      
      $filesLessInCommon = array (
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/1",
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/2",
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/1",
      "/Vol/1/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/2",
      "/Vol/2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/b/c/1",
      "/Vol/2/aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa/a/1",
      );
      
      $filesMoreInCommon = array (
      "/Voluuuuuuuuuuuuuumes/1/a/a/1",
      "/Voluuuuuuuuuuuuuumes/1/a/a/2",
      "/Voluuuuuuuuuuuuuumes/1/a/b/1",
      "/Voluuuuuuuuuuuuuumes/1/a/b/2",
      "/Voluuuuuuuuuuuuuumes/2/a/b/c/1",
      "/Voluuuuuuuuuuuuuumes/2/a/a/1",
      );
      
      $sameDir = array (
      "/Volumes/1/a/a/",
      "/Volumes/1/a/a/aaaaa/2",
      );
      
      $sameFile = array (
      "/Volumes/1/a/a/1",
      "/Volumes/1/a/a/1",
      );
      
      $noCommonPrefix = array (
      "/Volumes/1/a/a/",
      "/Volumes/1/a/a/aaaaa/2",
      "Net/1/a/a/aaaaa/2",
      );
      
      $longestLast = array (
      "/Volumes/1/a/a/1",
      "/Volumes/1/a/a/aaaaa/2",
      );
      
      $longestFirst = array (
      "/Volumes/1/a/a/aaaaa/1",
      "/Volumes/1/a/a/2",
      );
      
      $one = array ("/Volumes/1/a/a/aaaaa/1");
      
      $empty = array ( );
      
      
      // Test Results for finding  the common prefix
      
      /*
      
      I tested my functions in many possible scenarios.
      The results, the common prefixes, were always correct in all scenarios!
      Just try a function call with your individual array!
      
      Considering iteration efficiency, I also performed tests:
      
      I put echo functions into the functions where iterations occur, and measured the number of CLI line output via:
      php <script with strCommonPrefixByStr or strCommonPrefixByChar> | egrep "^  Str:" | wc -l   GIVES TOTAL ITERATION SUM.
      php <Script with strCommonPrefixByNeighbour> | egrep "^  Str:" | wc -l   PLUS   | egrep "^MATCH:" | wc -l   GIVES TOTAL ITERATION SUM.
      
      My hypothesis was proven:
      strCommonPrefixByChar wins in situations where the strings have less in common in their beginning (=prefix).
      strCommonPrefixByNeighbour wins where there is more in common in the prefixes.
      
      */
      
      // Test Results Table
      // Used Functions | Iteration amount | Remarks
      
      // $result = (strCommonPrefixByStr($filesLessInCommon)); // 35
      // $result = (strCommonPrefixByChar($filesLessInCommon)); // 35 // Same amount of iterations, but much fewer characters compared because ByChar instead of ByString!
      // $result = (strCommonPrefixByNeighbour($filesLessInCommon)); // 88 + 42 = 130 // Loses in this category!
      
      // $result = (strCommonPrefixByStr($filesMoreInCommon)); // 137
      // $result = (strCommonPrefixByChar($filesMoreInCommon)); // 137 // Same amount of iterations, but much fewer characters compared because ByChar instead of ByString!
      // $result = (strCommonPrefixByNeighbour($filesLeastInCommon)); // 12 + 4 = 16 // Far the winner in this category!
      
      echo("Common prefix of all members:\n");
      var_dump($result);
      
      
      
      
      
      // Tests for finding the shortest string in array
      
      /// Arrays
      
      // $empty = array ();
      // $noStrings = array (0,1,2,3.0001,4,false,true,77);
      // $stringsOnly = array ("one","two","three","four");
      // $mixed = array (0,1,2,3.0001,"four",false,true,"seven", 8888);
      
      /// Scenarios
      
      // I list them from fewest to most iterations, which is not necessarily equivalent to slowest to fastest!
      // For speed consider the remarks in the code considering the Speed ratio of foreach/for!
      
      //// Fewest iterations (immediate abort on "Found other type", use "for" loop)
      
      // foreach( array($empty, $noStrings, $stringsOnly, $mixed) as $arr) {
      //  echo("NEW ANALYSIS:\n");
      //  echo("Result: " . arrayStrLenMin($arr, true, true) . "\n\n");
      // }
      
      /* Results:
      
          NEW ANALYSIS:
          Result: Array is empty!
      
          NEW ANALYSIS:
          Result: Found other type!
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          0   Found first string member at key with length: 3!
          1   3
          2   5
          3   4
          Result: 3
      
          NEW ANALYSIS:
          Result: Found other type!
      
      */
      
      //// Fewer iterations (immediate abort on "Found other type", use "foreach" loop)
      
      // foreach( array($empty, $noStrings, $stringsOnly, $mixed) as $arr) {
      //  echo("NEW ANALYSIS:\n");
      //  echo("Result: " . arrayStrLenMin($arr, true, false) . "\n\n");
      // }
      
      /* Results:
      
          NEW ANALYSIS:
          Result: Array is empty!
      
          NEW ANALYSIS:
          Result: Found other type!
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          0   Found first string member at key with length: 3!
          0   3
          1   3
          2   5
          3   4
          Result: 3
      
          NEW ANALYSIS:
          Result: Found other type!
      
      */
      
      //// More iterations (No immediate abort on "Found other type", use "for" loop)
      
      // foreach( array($empty, $noStrings, $stringsOnly, $mixed) as $arr) {
      //  echo("NEW ANALYSIS:\n");
      //  echo("Result: " . arrayStrLenMin($arr, false, true) . "\n\n");
      // }
      
      /* Results:
      
          NEW ANALYSIS:
          Result: Array is empty!
      
          NEW ANALYSIS:
          Result: No strings found!
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          0   Found first string member at key with length: 3!
          1   3
          2   5
          3   4
          Result: 3
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          4   Found first string member at key with length: 4!
          5   No string!
          6   No string!
          7   5
          8   No string!
          Result: 4
      
      */
      
      
      //// Most iterations (No immediate abort on "Found other type", use "foreach" loop)
      
      // foreach( array($empty, $noStrings, $stringsOnly, $mixed) as $arr) {
      //  echo("NEW ANALYSIS:\n");
      //  echo("Result: " . arrayStrLenMin($arr, false, false) . "\n\n");
      // }
      
      /* Results:
      
          NEW ANALYSIS:
          Result: Array is empty!
      
          NEW ANALYSIS:
          Result: No strings found!
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          0   Found first string member at key with length: 3!
          0   3
          1   3
          2   5
          3   4
          Result: 3
      
          NEW ANALYSIS:
          Key Length / Notification / Error
          4   Found first string member at key with length: 4!
          0   No string!
          1   No string!
          2   No string!
          3   No string!
          4   4
          5   No string!
          6   No string!
          7   5
          8   No string!
          Result: 4
      
      */
      
      函数arrayStrLenMin($arr,$strictMode=false,$forLoop
      
      function prefix(strings) {
          switch (strings.length) {
      
            case 0:
              return "";
      
            case 1:
              return strings[0];
      
            case 2:
              // compute the prefix between the two strings
              var a = strings[0],
                  b = strings[1],
                  n = Math.min(a.length, b.length),
                  i = 0;
              while (i < n && a.charAt(i) === b.charAt(i))
                  ++i;
              return a.substring(0, i);
      
            default:
              // return the common prefix of the first string,
              // and the common prefix of the rest of the strings
              return prefix([ strings[0], prefix(strings.slice(1)) ]);
          }
      }
      
      def find_common_prefix_len(strings):
          """
          Given a list of strings, finds the length common prefix in all of them.
          So
          apple
          applet
          application
          would return 3
          """
          prefix          = 0
          curr_index      = -1
          num_strings     = len(strings)
          string_lengths  = [len(s) for s in strings]
          while True:
              curr_index  += 1
              ch_in_si    = None
              for si in xrange(0, num_strings):
                  if curr_index >= string_lengths[si]:
                      return prefix
                  else:
                      if si == 0:
                          ch_in_si = strings[0][curr_index]
                      elif strings[si][curr_index] != ch_in_si:
                          return prefix
              prefix += 1
      
      
          // Common prefix
          $common = '';
      
          $sports = array(
          'Softball T - Counties',
          'Softball T - Eastern',
          'Softball T - North Harbour',
          'Softball T - South',
          'Softball T - Western'
          );
      
          // find mini string
          $minLen = strlen($sports[0]);
          foreach ($sports as $s){
              if($minLen > strlen($s))
                  $minLen = strlen($s);
          }
      
      
          // flag to break out of inner loop
          $flag = false;
      
          // The possible common string length does not exceed the minimum string length.
          // The following solution is O(n^2), this can be improve.
          for ($i = 0 ; $i < $minLen; $i++){
              $tmp = $sports[0][$i];
      
              foreach ($sports as $s){
                  if($s[$i] != $tmp)
                      $flag = true;
              }
              if($flag)
                  break;
              else
                  $common .= $sports[0][$i];
          }
      
          print $common;
      
      /// Return length of longest common prefix in an array of strings.
      function _commonPrefix($array) {
          if(count($array) < 2) {
              if(count($array) == 0)
                  return false; // empty array: undefined prefix
              else
                  return strlen($array[0]); // 1 element: trivial case
          }
          $len = max(array_map('strlen',$array)); // initial upper limit: max length of all strings.
          $prevval = reset($array);
          while(($newval = next($array)) !== FALSE) {
              for($j = 0 ; $j < $len ; $j += 1)
                  if($newval[$j] != $prevval[$j])
                      $len = $j;
              $prevval = $newval;
          }
          return $len;
      }
      
      // TEST CASE:
      $arr = array('/var/yam/yamyam/','/var/yam/bloorg','/var/yar/sdoo');
      print_r($arr);
      $plen = _commonprefix($arr);
      $pstr = substr($arr[0],0,$plen);
      echo "Res: $plen\n";
      echo "==> ".$pstr."\n";
      echo "dir: ".dirname($pstr.'aaaa')."\n";
      
      Array
      (
          [0] => /var/yam/yamyam/
          [1] => /var/yam/bloorg
          [2] => /var/yar/sdoo
      )
      Res: 7
      ==> /var/ya
      dir: /var
      
      function findLongestPrefix($arr) {
        return array_reduce($arr, function($prefix, $item) {
          $length = min(strlen($prefix), strlen($item));
          while (substr($prefix, 0, $length) !== substr($item, 0, $length)) {
            $length--;
          }
          return substr($prefix, 0, $length);
        }, $arr[0]);
      }
      
      print findLongestPrefix($sports); // Softball -
      
      /**
       * Try to find a common prefix for a list of strings
       * 
       * @param array $strings
       * @return string
       */
      function findCommonPrefix(array $strings)
      {
          $prefix = '';
          $chars = array_map("str_split", $strings);
          $matches = call_user_func_array("array_intersect_assoc", $chars);
          if ($matches) {
              $i = 0;
              foreach ($matches as $key => $value) {
                  if ($key != $i) {
                      unset($matches[$key]);
                  }
                  $i++;
              }
              $prefix = join('', $matches);
          }
      
          return $prefix;
      }
      
      function product_name_intersection($array){
      
          $pl = 0; // common prefix length
          $n = count($array);
          $l = strlen($array[0]);
          $first = current($array);
      
          while ($pl < $l) {
              $c = $array[0][$pl];
              for ($i=1; $i<$n; $i++) {
                  if (!isset($array[$i][$pl]) || $array[$i][$pl] !== $c) break 2;
              }
              $pl++;
          }
          $prefix = substr($array[0], 0, $pl);
      
          if ($pl < strlen($first) && substr($prefix, -1, 1) != ' ') {
      
              $prefix = preg_replace('/\W\w+\s*(\W*)$/', '$1', $prefix);
          }
      
          $prefix =  preg_replace('/^\W*(.+?)\W*$/', '$1', $prefix);
      
          return $prefix;
      }