dizelerin dizi ortak bir önek bulma

12 Cevap php

Ben böyle bir dizi var

$sports = array(
'Softball - Counties',
'Softball - Eastern',
'Softball - North Harbour',
'Softball - South',
'Softball - Western'
);

and i would like to find the longest common part of the string so in this instance, it would be 'Softball - ';

Ben bu süreci takip edeceğini düşünüyorum

$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

Sorular

  1. Bunu yapmanın bir fonksiyon inşa veya daha basit bir yolu var mı?

  2. Muhtemelen iyi, ama birkaç bin satır diziler yapmak olsaydı, yükü bir sürü olurdu, bu yüzden $ i benim başlangıç ​​değerleri ile hesaplanan hareket olması, örneğin $ i = yarım olurdu benim 5 satır dizisi için eğer başarısız biz başarılı kadar dize, o $ i / 2 çalıştığını kadar, sonra 1 ile $ i artırmak. Bir sonuç elde etmek için karşılaştırmalar az sayıda yapıyoruz böylece

Bu tür sorunları için zaten orada bir formül / algoritma çıkışı var mı?

teşekkürler

alex

12 Cevap

Ben bu sonuçla, kod içine @ diogoriba algoritması uygulanmaktadır:

  • İlk iki dizeleri ortak bir önek bulma ve ortak hiçbir şey bulursa sonra tüm aşağıdaki dizeler 3 başlayarak, ve ortak dize Döşeme ile karşılaştırarak, farklı daha önek ortak daha var durumlarda kazanır.
  • Dizeleri farklı daha kendi önek ortak daha az var Ama nerede (onarımları hariç) bumperbox orijinal algoritması kazanır. Details in the code comments!

Ben hayata başka bir fikir:

İlk dizi kısa dize kontrol ve karşılaştırma yerine, sadece ilk dize için kullanabilirsiniz. In the code, this is implemented with the custom written function arrayStrLenMin().

  • Dramatik tekrarlamalar aşağı getirebilir, ancak işlevi arrayStrLenMin () kendisi (veya daha az) tekrarlamalar neden olabilir.
  • Basitçe dizideki İlk dizenin uzunluğu ile başlayan oldukça hantal görünüyor, ama arrayStrLenMin () birçok yineleme ihtiyacı varsa, etkili ortaya çıkabilir.

Get the maximum common prefix of strings in an array with as little iterations as possible (PHP)

Code + Extensive Testing + Remarks:

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

*/

Bu kullanabilirsiniz:

$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;
    }
}

Update   Here’s another solution, iteratively comparing each n-th character of the strings until a mismatch is found:

$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);

commonPrefixLength atom karşılaştırmaları numberOfStrings · en yalnızca olduğu gibi bu daha verimlidir.

Muhtemelen orada bunun için bazı korkunç saygın bir algoritma, ama sadece kafamın üst kapalı, bilirsin eğer ortak sizin örnekteki gibi sol tarafta olacak, size gönderdi metodoloji yol daha iyi yapabilirdi Önce ilk iki dizeleri ortaklığı bulma ve ardından listenin geri kalanı aşağı yineleme, benzerliği elde etmek için gerekli ortak dize kırparak ya da hiçbir şey için tüm yolu Döşeme eğer yetmezliği ile sonlanan tarafından.

Ben doğru yolda olduğunu düşünüyorum. Ama bunun yerine dize tüm geçtiğinde i arttırma, bunu yapabilirsiniz:

1) dizideki ilk 2 dizeleri karşılaştırın ve onlar kaç ortak karakter bulmak. Örneğin, maxCommon adlı ayrı bir dize ortak karakterleri kaydedin.

2) maxCommon w / üçüncü dize karşılaştırın. Ortak karakter sayısı küçükse, maç karakter maxCommon Döşeme.

3) tekrar ve dizinin geri kalanı için durulayın. İşlemin sonunda, maxCommon dizi elemanları için ortak olan dize sahip olacaktır.

Bu maxCommon / w her dize karşılaştırmak gerekir, çünkü bazı havai katacak, ama büyük ölçüde sizin sonuçlarını almak gerekir iterasyon sayısını azaltacaktır.

Ben "ortak bir parçası" ederek "en uzun ortak bir önek" demek olduğunu varsayalım. Yani herhangi bir ortak substring daha hesaplamak için bir çok daha kolaydır.

Bu n uzun ortak önek uzunluğu ve {[iyi durumda, kötü durumda ve n * m + 1 in (n+1) * m karakter okumadan yapılamaz (3)]} dizeleri sayısıdır.

Bir seferinde bir harf karşılaştırarak elde bu verimlilik (Büyük Teta (n * m)).

Sizin önerilen algoritma geniş girişler için çok yavaş, çok olan, Büyük Teta (n ^ 2 * m) çalışır.

Üçüncü, dördüncü, vs ile de Büyük Teta (n * m) çalışan bir zaman olduğunu karşılaştırarak sonra, ilk iki dizeleri uzun önek bulma, ancak daha yüksek bir sabit bir katsayı ile üçüncü Önerilen algoritma. Muhtemelen sadece pratikte biraz daha yavaş olacaktır.

Ilk algoritma çok yavaş ve iki diğerleri hakkında eşit zaten yazmak için karmaşık olacağından Genel olarak, ben sadece kendi işlevini haddeleme öneriyoruz.

Büyük Teta gösterimde açıklaması için WikiPedia göz atın.

İşte JavaScript zarif, özyinelemeli uygulama bulunuyor:

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)) ]);
    }
}
  1. Ben bilmiyorum ki

  2. evet: yerine uzunluk i 0'dan altdize karşılaştırarak, sadece (zaten bu karakterler 0 i-1 maç bilmek) i'inci karakteri kontrol edebilirsiniz.

Kısa ve tatlı versiyonu, belki de en verimli değil:

/// 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";

Test davanın Çıktı:

Array
(
    [0] => /var/yam/yamyam/
    [1] => /var/yam/bloorg
    [2] => /var/yar/sdoo
)
Res: 7
==> /var/ya
dir: /var

@bumperbox

  1. Sizin temel kod TÜM senaryolarda çalışmak için bazı düzeltme gerekli!

    • Sizin döngü yalnızca son karakterinden önce bir karakter kadar karşılaştırır!
    • Uyumsuzluk muhtemelen son ortak karakterinden sonra 1 döngü döngü oluşabilir.
    • Dolayısıyla en azından ilk dize'nın son karakterden sonra 1 karaktere kadar kontrol etmelisiniz.
    • Dolayısıyla karşılaştırma operatörü "<= 1" veya "<2" olmalıdır.
  2. Şu anda sizin algoritma başarısız

    • İlk dize tamamen diğer tüm dizeler dahil edilmesi halinde,
    • veya tamamen son karakter dışındaki diğer tüm dizeleri dahil.

Benim sonraki cevap / yazı, ben yineleme optimize kod eklenecektir!

Original Bumperbox code PLUS correction (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));

Nasıl böyle bir şey? Bu daha biz boş sonlandırma karakterini kullanabilirsiniz eğer dizeleri uzunlukları kontrol etmek zorunda değil tarafından optimize edilebilir (ama Python dizeleri uzunluğu yerde önbelleğe varsayarak yaşıyorum?)

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

Ben böyle bir özyinelemeli algoritmayı kullanmak istiyorsunuz:

1 - get the first string in the array 2 - call the recursive prefix method with the first string as a param 3 - if prefix is empty return no prefix 4 - loop through all the strings in the array 4.1 - if any of the strings does not start with the prefix 4.1.1 - call recursive prefix method with prefix - 1 as a param 4.2 return prefix

Burada çözüm dizelerinin başında ortaklıkları bulmak için sadece çalışabilir. İşte dizelerden oluşan bir dizi uzun ortak alt dize anywhere arar bir işlevdir.

http://www.christopherbloom.com/2011/02/24/find-the-longest-common-substring-using-php/