Nasıl daha verimli hale getirmek için benim PHP kodu artırabilir?

11 Cevap php

Ben rastgele bir değer geçerli Rugby puan olup olmadığını denetler basit bir PHP komut dosyası yazdık. Oldukça güzel çalışıyor ama özellikle verimli değildir, onu geliştirmeye herhangi bir tavsiye çok hoş olurdu.

$score = rand(0, 60);

/* Rugby Union
 * 
 * Try = 5 points
 * Conversion = 2 points
 * Penalty = 3 points
 * Drop goal = 3 points
 * 
 */

echo "<h1>Score: ".$score."</h1>";

for ($tries = 0; $tries <= 12; $tries++)
{
	for ($conversions = 0; $conversions <= 30; $conversions++)
 	{
		for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++)
 		{
 			if ($conversions > $tries)
 			{
 				//echo "<br />Illegal score";
 			}
 			else
 			{
 				$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
 				if ($testscore == $score)
 				{
 					if ($dropgoals == 0)
 					{
 						echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
 					}
 					else
 					{
 						echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
 					}
 				}
 			}
 		}
 	}
}

Bunun mümkün olmadığını döngüler için iç içe miktarını azaltmak için güzel olurdu, haliyle, tamam revize çözüm ...

echo "<h1>Score: ".$score."</h1>";

for ($tries = 0; $tries <= 12; $tries++) {
    for ($conversions = 0; $conversions <= $tries; $conversions++) {
        for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
    		if ($conversions <= $tries) {
    				$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
                    if ($testscore == $score) {
     					echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");
     				}
    		}
        }
    }
}

11 Cevap

Iyi bir başlangıç ​​için

for ($conversions = 0; $conversions <= 30; $conversions++)

değiştirebilirsiniz

for ($conversions = 0; $conversions <= $tries; $conversions++)

Pratik konuşma, orada olası puan sadece bir sonlu dizi, değil mi? Hızlı Google rekor 164 puan olduğunu göstermektedir. Peki neden app belli bir max (300? 500?), Ve sabit-kodu o kadar, bir kez, mümkün olan her puanı bir listesini oluşturmak değil. Verilen skor listesinde ise o, zamanında, sadece kontrol. O, şimdiye kadar, en etkili çözüm olacağını düşünüyorum.

Edit: da çıktı denemeden, cezalar istiyorsanız bu yöntem hala çalışır ve hedefleri damla - sadece o değerler üretmek, çok - bir kez - ve bir olarak (aynı zamanda listede tutmak iki-boyutlu bir dizi veya bir ilişkisel dizi).

Eğer "verimli" derken, ne demek tanımlamak lütfen.

Kod çok yavaş yürütülüyor? Ne kadar hızlı o şimdi çalışıyor, ve bunu ne kadar hızlı çalıştırmak gerekiyor? Eğer "yeterince hızlı değil" tanımlamak yapamıyorsanız o zaman bir hedefim yok.

Eğer hızlandırmak için ne tahmin gitmeden önce, burada tüm katılımcıların scattershot kat hızlanma yapmaya teşvik ederek size bir kötülük yapmadan önce, bu çoğu zaman nerede harcandığının görmek için kod profil gerekir.

Lütfen eğer başka işlevi ters olmalıdır. If () {} maddesinin içine en olası senaryo comme yapmak, ve else istisnai hata {}

if ($conversions < $tries)
                        {
                                $testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
                                if ($testscore == $score)
                                {
                                        if ($dropgoals == 0)
                                        {
                                                echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
                                        }
                                        else
                                        {
                                                echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
                                        }
                                }
                        }
                        else
                        {
                              // echo "illegal score";
                        }

Bu biraz şeyleri temizlemek olacaktır.

echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");

Biraz değiştirilmiş bir versiyonu. Ben rugby hakkında daha fazla bilseydim.

$score = rand(0, 60);

/* Rugby Union
 * 
 * Try = 5 points
 * Conversion = 2 points
 * Penalty = 3 points
 * Drop goal = 3 points
 * 
 */

echo "<h1>Score: ".$score."</h1>";

for ($tries = 0; $tries <= 12; $tries++){
    for ($conversions = 0; $conversions <= $tries; $conversions++){
    	for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
    		else{
    			$testscore = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
    			if ($testscore == $score){
    				if ($dropgoals == 0){
    					echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals.<br />";
    				}
    				else{
    					echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals." drop goals or penalties.<br />";
    				}
    			}
    		}
    	}
    }
    if ($conversions > $tries){
    	echo "<br />Illegal score";
    }
}

Ayrıca bir çözüm buldum zaman döngüler patlak verebilir:

if ($testscore == $score) 
{
  echo "Found a way to achieve ....";
  break 3;
}

Yazma anda 3 for çıkmak için döngüler vardı bu yüzden sayı, patlak döngü sayısını belirtir.

Yeah 3 foor loops seem to be too much for such a problem. But as you want to find a combination x,y,z, such that n = x*5 + y*3 + z*2 with x>=z, I don't think there is a simpler solution. You can however reduce the number of iterations.
And it would be good to know if you want to get all possible combinations or just an answer like 'Yes, this is a valid score'.

Her neyse, bu benim önerilerdir:

$score = rand(0, 60);

/* Rugby Union
 * 
 * Try = 5 points
 * Conversion = 2 points
 * Penalty = 3 points
 * Drop goal = 3 points
 * 
 */

// compute how often the points fit into the score
$maxTries = intval($score / 5);
$maxConversions = min(intval($score / 2),$maxTries);
$maxDrops = intval($score / 3);

$valid = false;
for ($tries = 0; $tries <= $maxTries; $tries++)
{   
    // this way, you avoid recomputing the value over and over again in the third loop 
    $scoreTries = $tries * 5;
    for ($conversions = 0; $conversions <= $maxConversions; $conversions++)
    {
        $scoreCons = $scoreTries  + $conversions * 2;
        for ($dropgoals = 0; $dropgoals <= $maxDrops; $dropgoals++)
        {
            $scoreTotal = $scoreCons + $dropgoals * 3
            if ($scoreTotal == $score)
            {
               echo 'Found a way to achieve score with '.$tries.' tries '.$conversions.' conversions and '.$dropgoals.' drop goals or penalties.<br />';
               $valid = true;
               // write 'break 3' here if you are satisfied with one answer                
            }
        }
    }
}

if (!$valid){
    echo "<br />Illegal score";
}

Ben verimliliği geliştirir ne kadar bilmiyorum ama genel olarak bunları bağlamak için 'nokta' sözdizimi kullanırsanız tek tırnak ('string') dizeleri çevrelemek için her zaman iyidir. Bu şekilde, PHP, benim görüşüme göre, temiz bir yaklaşım olduğu yerine değişkenler için dizeleri değerlendirmek değil.

Edit:

Eg arasında hiçbir fark mantıklı olduğundan Oh ve ben, $dropgoals == 0 arasında ayrım yoktur ...and 0 drop goals. ve ...and 0 drop goals or penalties.

Sizin yaklaşım daha da geliştirilebilir - yerine üç değişkenin tüm kombinasyonları ile seyir - çalışır, dönüşümler ve dropgoals, sadece aşmayın bu kombinasyonların bakabilirsiniz $score. Hala iç içe döngüler olmasına rağmen, döngü içindeki kod çalıştırılır kez sayısı azalmıştır. Aşağıya bakın.

echo "<h1>Score: ".$score."</h1>";

$triesScore = 5;
$conversionsScore = 2;
$dropgoalsScore = 3;

for ($tries = 0; $tries <= $score/$triesScore; $tries++) {
    for ($conversions = 0; $conversions <= ($score-$triesScore*$tries)/$conversionsScore; $conversions++) {
        for ($dropgoals = 0; $dropgoals <= ($score-$triesScore*$tries-$conversionsScore*$conversions)/$dropgoalsScore; $dropgoals++){
            $testscore = ($tries * $triesScore) + ($conversions * $conversionsScore) + ($dropgoals * $dropgoalsScore);
            if ($testscore == $score) {
                echo "Found a way to achieve score with ".$tries." tries ".$conversions." conversions and ".$dropgoals.($dropgoals == 0 ? " drop goals.<br />" : " drop goals or penalties.<br />");
            }
        }
    }
}

Gerçekte olsa, 60 bir max-skor için, gelişmeler onlar farkedilemez olabilir, çok küçük.

Bu belirli bir miktarda değişim mezheplerin kümesi verilen paralar kadar yapılabilir nasıl bulmak gibi aynı sorun var. İşte PHP bir uygulama bulunuyor. Ben çok verimli ise şüpheliyim, ancak iç içe döngü sürümü daha genel bulunuyor.

<?php

f(
  30, // points scored in match
  array( // rugby union scoring structure
    "Converted Tries" => 7,
    "Unconverted Tries" => 5,
    "Drop Goals/Penalties" => 3,
  )
);

function f($points_left, $scoring_structure, $scores_so_far = array()){
  if($points_left==0){
    print_score($scores_so_far);
  }else if($points_left>0){
    if($scoring_structure){
      list($score_type, $points_for_score_type) =
        first_element($scoring_structure);

      // Option 1: Use a highest-denomination coin,
      // and make change for the rest.
      if($points_for_score_type <= $points_left){
        f(
          $points_left-$points_for_score_type,
          $scoring_structure,
          increment($scores_so_far,$score_type)
        );  
      }

      // Option 2: Attempt to make change for the full amount without
      // using the highest denomination coin at all.
      f(
        $points_left,
        all_except_first_element($scoring_structure),
        $scores_so_far
      );
    }
  }else{
    exit("Error: Should never reach here!\n");
  }
}

function increment($arr, $key){
 $arr[$key]++;
 return $arr;
}

function all_except_first_element($arr){
  list($k, $v) = first_element($arr);
  unset($arr[$k]);
  return $arr;
}

function first_element($arr){
  foreach($arr as $k=>$v){
    return array($k, $v);
  }
}

function print_score($scores_so_far){
  $parts = array();
  foreach($scores_so_far as $k=>$v){
    $parts[]= "$k: $v";
  }
  echo implode(", ", $parts), "\n";
}

Precompute! Ben performans app öldürür şüpheliyim, ama sadece durumda düşündüm. Orada 1911 olası kombinasyonları ve 141 geçerli puanları, böylece kolayca veri precompute olabilir ve bu diskte saklamak ve gerektiğinde yükleyebilirsiniz.

Precomputing:

$scores = array();
for ($tries = 0; $tries <= 12; $tries++) {
    for ($conversions = 0; $conversions <= $tries; $conversions++) {
        for ($dropgoals = 0; $dropgoals <= 20; $dropgoals++){
            $score = ($tries * 5) + ($conversions * 2) + ($dropgoals * 3);
            if( !array_key_exists($score,$scores) ) $scores[$score] = array();
            $scores[$score][] = array( $tries, $conversions, $dropgoals );
        }
    }
}

echo "number of unique possible scores is " . count($scores) . "\n";
$number_combinations = 0;
foreach( $scores as $score => $combinations ) {
    echo "Score " . $score . " has " . count($combinations) . " combinations\n";
    $number_combinations += count($combinations);
}
echo "number of unique combinations is " . $number_combinations . "\n";

// store
file_put_contents("scores.txt",serialize($scores));

Arama:

$scores=unserialize(file_get_contents("scores.txt"))
$number_of_combinations_for_score_23 = array_key_exists(23,$scores) ? count($scores[23]) : 0;

Hatta sağ tarafta sadece "geçerli veya değil" bool içeren puanlar dizi azaltabilir. Bu biraz arama zaman ve yer kazandırır.