如何优化这个数组循环

时间:2013-09-26 16:37:06

标签: php arrays

我有一个数组,其中包含许多航班的信息。我只想要五个最低价格。

首先,我按价格对数组进行排序。

其次我打印前五个阵列

但需要更多时间......我怎样才能减少这段时间?

foreach ($flights_result->json_data['response']['itineraries'] as $key => $value)
{
    $mid[$key] = $value['price']['totalAmount'];
}

//Sort the data with mid descending
//Add $data as the last parameter, to sort by the common key
array_multisort($mid, SORT_ASC, $flights_result->json_data['response']['itineraries']);

// print 5 arrays
foreach ($flights_result->json_data['response']['itineraries'] as  $value)
{
    echo 'departureTime:' . $value['inboundInfo']['departureTime'] . '</br>';
    echo 'layoverInMin:' . $value['inboundInfo']['layoverInMin'] . '</br>';
    //      // loop echo 

    foreach ($value['inboundInfo']['flightNumbers'] as $flightNumbers)
    {
        echo 'flightNumbers  :' . $flightNumbers . '</br>';
    }

    echo 'durationInMin:' . $value['inboundInfo']['durationInMin'] . '</br>';
    echo 'localDepartureTimeStr:' . $value['inboundInfo']['localDepartureTimeStr'] . '</br>';
    echo ' arrivalTime:' . $value['inboundInfo']['arrivalTime'] . '</br>';
    echo ' numStops:' . $value['inboundInfo']['numStops'] . '</br>';

    ////     loop 
    foreach ($value[' inboundInfo']['flightClasses'] as $flightClasses)
    {
        echo 'flightClasses name :' . $flightClasses['name'] . '</br>';
        echo 'flightClasses fareClass :' . $flightClasses['fareClass'] . '</br>';
    }

    echo 'localArrivalTimeStr:' . $value['inboundInfo']['localArrivalTimeStr'] . '</br>';
    //      loop  echo

    foreach ($value[' carrier'] as $carrier)
    {
        echo 'carrier name :' . $carrier['name'] . '</br>';
        echo 'carrier code :' . $carrier['code'] . '</br>';
    }

    echo 'amount:' . $value['price']['amount'] . '</br>';
    echo ' totalAmount :' . $value['price']['totalAmount'] . '</br>';
    echo 'pricePerPassenger:' . $value['price']['pricePerPassenger'] . '</br>';
    echo 'currencyCode: ' . $value['price']['currencyCode'] . '</br>';
    echo 'totalPricePerPassenger: ' . $value['price']['totalPricePerPassenger'] . '</br>';
    echo 'includesTax: ' . $value['price ']['includesTax'] . '</br>';
    echo 'destinationCountryCode:' . $value[' destinationCountryCode'] . ' </br> -------- </br>';

    $count++;
    if ($count > 2)
    {
        break;
    }
}

数组示例

Array
(
    [0] => Array
        (
            [ecpcRank] => 0
            [inboundInfo] => Array
                (
                    [aircraftTypes] => Array
                        (
                        )

                    [departureTime] => 1381448400000
                    [layoverInMin] => 1359
                    [flightNumbers] => Array
                        (
                            [0] => DL3672
                            [1] => EK204
                            [2] => EK923
                        )

                    [durationInMin] => 2360
                    [airportsExpanded] => Array
                        (
                            [0] => PHL
                            [1] => JFK
                            [2] => JFK
                            [3] => DXB
                            [4] => DXB
                            [5] => CAI
                        )

                    [localDepartureTimeStr] => 2013/10/10 18:40 -0500
                    [airports] => Array
                        (
                            [0] => PHL
                            [1] => JFK
                            [2] => DXB
                            [3] => CAI
                        )

                    [arrivalTime] => 1381590000000
                    [numStops] => 2
                    [flightClasses] => Array
                        (
                            [0] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [1] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [2] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                        )

                    [localArrivalTimeStr] => 2013/10/12 17:00 +0200
                )

            [location] => Array
                (
                    [0] => Array
                        (
                            [code] => CAI
                            [name] => Cairo
                        )

                    [1] => Array
                        (
                            [code] => DXB
                            [name] => Dubai
                        )

                    [2] => Array
                        (
                            [code] => PHL
                            [name] => Philadelphia
                        )

                    [3] => Array
                        (
                            [code] => JFK
                            [name] => New York J F Kennedy
                        )

                    [4] => Array
                        (
                            [code] => MXP
                            [name] => Milan Malpensa
                        )

                )

            [carrier] => Array
                (
                    [0] => Array
                        (
                            [name] => Delta Air Lines
                            [code] => DL
                        )

                    [1] => Array
                        (
                            [name] => US Airways
                            [code] => US
                        )

                    [2] => Array
                        (
                            [name] => Emirates
                            [code] => EK
                        )

                    [3] => Array
                        (
                            [name] => Egyptair
                            [code] => MS
                        )

                )

            [bookingType] => WEBSITE
            [price] => Array
                (
                    [name] => 
                    [nameOTA] => 
                    [description] => 
                    [amount] => 26280
                    [totalAmount] => 26280
                    [pricePerPassenger] => 26280
                    [currencyCode] => EGP
                    [totalPricePerPassenger] => 26280
                    [includesTax] => 1
                )

            [generatedDate] => 1380212804686
            [providerId] => emirates.com
            [id] => MS703[CAI-MXP],EK205[MXP-JFK],US3407[JFK-PHL]|DL3672[PHL-JFK],EK204[JFK-DXB],EK923[DXB-CAI]
            [originCountryCode] => EG
            [bookingCode] => 13600077136293253
            [destinationCountryCode] => US
            [outboundInfo] => Array
                (
                    [aircraftTypes] => Array
                        (
                        )

                    [departureTime] => 1380958800000
                    [layoverInMin] => 1050
                    [flightNumbers] => Array
                        (
                            [0] => MS703
                            [1] => EK205
                            [2] => US3407
                        )

                    [durationInMin] => 1940
                    [airportsExpanded] => Array
                        (
                            [0] => CAI
                            [1] => MXP
                            [2] => MXP
                            [3] => JFK
                            [4] => JFK
                            [5] => PHL
                        )

                    [localDepartureTimeStr] => 2013/10/05 09:40 +0200
                    [airports] => Array
                        (
                            [0] => CAI
                            [1] => MXP
                            [2] => JFK
                            [3] => PHL
                        )

                    [arrivalTime] => 1381075200000
                    [numStops] => 2
                    [flightClasses] => Array
                        (
                            [0] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [1] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [2] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                        )

                    [localArrivalTimeStr] => 2013/10/06 11:00 -0500
                )

        )

    [1] => Array
        (
            [ecpcRank] => 0
            [inboundInfo] => Array
                (
                    [aircraftTypes] => Array
                        (
                        )

                    [departureTime] => 1381448400000
                    [layoverInMin] => 1359
                    [flightNumbers] => Array
                        (
                            [0] => DL3672
                            [1] => EK204
                            [2] => EK923
                        )

                    [durationInMin] => 2360
                    [airportsExpanded] => Array
                        (
                            [0] => PHL
                            [1] => JFK
                            [2] => JFK
                            [3] => DXB
                            [4] => DXB
                            [5] => CAI
                        )

                    [localDepartureTimeStr] => 2013/10/10 18:40 -0500
                    [airports] => Array
                        (
                            [0] => PHL
                            [1] => JFK
                            [2] => DXB
                            [3] => CAI
                        )

                    [arrivalTime] => 1381590000000
                    [numStops] => 2
                    [flightClasses] => Array
                        (
                            [0] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [1] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [2] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                        )

                    [localArrivalTimeStr] => 2013/10/12 17:00 +0200
                )

            [location] => Array
                (
                    [0] => Array
                        (
                            [code] => CAI
                            [name] => Cairo
                        )

                    [1] => Array
                        (
                            [code] => PHL
                            [name] => Philadelphia
                        )

                    [2] => Array
                        (
                            [code] => DXB
                            [name] => Dubai
                        )

                    [3] => Array
                        (
                            [code] => JFK
                            [name] => New York J F Kennedy
                        )

                )

            [carrier] => Array
                (
                    [0] => Array
                        (
                            [name] => Delta Air Lines
                            [code] => DL
                        )

                    [1] => Array
                        (
                            [name] => Emirates
                            [code] => EK
                        )

                )

            [bookingType] => WEBSITE
            [price] => Array
                (
                    [name] => 
                    [nameOTA] => 
                    [description] => 
                    [amount] => 28183
                    [totalAmount] => 28183
                    [pricePerPassenger] => 28183
                    [currencyCode] => EGP
                    [totalPricePerPassenger] => 28183
                    [includesTax] => 1
                )

            [generatedDate] => 1380212804689
            [providerId] => emirates.com
            [id] => EK928[CAI-DXB],EK203[DXB-JFK],DL6122[JFK-PHL]|DL3672[PHL-JFK],EK204[JFK-DXB],EK923[DXB-CAI]
            [originCountryCode] => EG
            [bookingCode] => 13600077139546083
            [destinationCountryCode] => US
            [outboundInfo] => Array
                (
                    [aircraftTypes] => Array
                        (
                        )

                    [departureTime] => 1380966900000
                    [layoverInMin] => 947
                    [flightNumbers] => Array
                        (
                            [0] => EK928
                            [1] => EK203
                            [2] => DL6122
                        )

                    [durationInMin] => 2118
                    [airportsExpanded] => Array
                        (
                            [0] => CAI
                            [1] => DXB
                            [2] => DXB
                            [3] => JFK
                            [4] => JFK
                            [5] => PHL
                        )

                    [localDepartureTimeStr] => 2013/10/05 11:55 +0200
                    [airports] => Array
                        (
                            [0] => CAI
                            [1] => DXB
                            [2] => JFK
                            [3] => PHL
                        )

                    [arrivalTime] => 1381093980000
                    [numStops] => 2
                    [flightClasses] => Array
                        (
                            [0] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [1] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                            [2] => Array
                                (
                                    [name] => Economy
                                    [fareClass] => 1
                                )

                        )

                    [localArrivalTimeStr] => 2013/10/06 16:13 -0500
                )

        )

8 个答案:

答案 0 :(得分:4)

回答你的问题:

  

但需要更多的时间......如何减少这个大时间?

在减少之前,您需要确切了解 more 的确切位置。正如您在评论中所写,您正在使用远程请求来获取数据。

为数组排序您提供的数据非常快,因此我假设您不需要优化数组排序,而只需要从远程获取数据的方式和方式。一种方法是缓存它或预取它或进行并行处理。但到目前为止的细节根本不重要,除非你已经发现更多来自哪里,以便明确什么是大时间,所以可以考虑减少它。

希望到目前为止这是有用的,并随意将缺少的信息添加到您的问题中。

你可以在这里看到只有阵列的代码,它真的很快:

您可以在输出正下方找到执行统计信息,例如:

  

确定(真实的0.008秒,墙壁的0.006秒,14 MB,99个系统调用)

答案 1 :(得分:2)

你应该真正安装一个profiler (XHProf)并检查确切需要花费多少时间。

我认为这是排序,因为foreach通过5个元素的最终数组应该快速点亮。你为什么要这样排序呢?如果排序的唯一目的是找到5个“最低”的项目,那么最快的方法就是找到5个最低的项目:

$min5 = array();
foreach ($flights_result->json_data['response']['itineraries'] as $key => $value)
{
    $amount = $value['price']['totalAmount'];

    // Just put first 5 elements in our result array
    if(count($min5) < 5) {
        $min5[$key] = $amount;
        continue;
    }
    // Find largest element of those 5 we check
    $maxMinK = null;
    foreach($min5 as $minK=>$minV) {
        if($maxMinK === null) {
            $maxMinK = $minK;
            continue;
        }
        if($minV > $min5[$maxMinK])
        {
            $maxMinK = $minK;
        }
    }
    // If our current amount is less than largest one found so far,
    // we should remove the largest one and store the current amount instead
    if($amount < $min5[$maxMinK])
    {
        unset($min5[$maxMinK]);
        $min5[$key] = $amount;
    }
}
asort($min5); // now we can happily sort just those 5 lowest elements

它会找到大约O(6n)的5个项目,在您的情况下,应该优于潜在的O(n²)进行排序;然后你可以像以下一样使用它:

foreach($min5 as $key=>$minValue)
{
    $intinerary = $flights_result->json_data['response']['itineraries'][$key]
    ...
}

这应该快得多,只要排序!所以得到XHprof并检查:)

答案 2 :(得分:1)

这就是我要做的事情:

<?php

    // Initialize html Array
    $html = array();

    // Iterate Over Values, Using Key as Label.
    foreach( $value['inboundInfo'] as $inboundLabel => &$inboundValue )
    {
        // Check for Special Cases While Adding to html Array
        if( $inboundLabel == 'flightNumbers' )
        {
            $html[] = $inboundLabel . ': ' . implode( ', ', $inboundValue );
        }
        elseif( $inboundLabel == 'flightClasses' )
        {
            foreach( $inboundValue as $fcName => &$fcValue )
            {
                $html[] = 'flightClasses ' . $fcName . ': ' . $fcValue;
            }
        }
        else
        {
            $html[] = $inboundLabel . ': ' . $inboundValue;
        }
    }

    // Don't Need Foreach to Complicate Things Here
    $html[] = 'carrier name: ' . $value[' carrier']['name'];
    $html[] = 'carrier code: ' . $value[' carrier']['code'];

    // Add Price Info to Array
    foreach( $value['price'] as $priceLabel => &$price )
    {
        $html[] = $priceLabel . ': ' . $price;
    }
    $html[] = ' -------- </br>';

    // And Finally:
    echo implode( "<br/>\r\n", $html );

它要么是要么写一个递归函数来遍历所有数据。另请注意,这仅适用于您的数据符合您想要的顺序。

答案 3 :(得分:0)

我会做以下事情:

// This is optional, it just makes the example more readable (IMO)
$itineraries = $flights_result->json_data['response']['itineraries'];

// Then this should sort in the smallest way possible
foreach ($flights_result->json_data['response']['itineraries'] as $key => $value) {
     $mid[$key] = $value['price']['totalAmount'];
}

// Sort only one array keeping the key relationships.
asort($mid);

// Using the keys in mid, since they are the same as the keys in the itineraries
// we can get directly to the data we need.
foreach($mid AS $key => $value) {
     $value = $itineraries[$key];

     // Then continue as above, I think your performance issue is the sort
     ...
}

答案 4 :(得分:0)

缓冲回波/打印(即,不从内部循环回显/打印):

$buffer = "";

for ($i = 0; $i < 1000; $i++) {
    $buffer .= "hello world\n";
}

print($buffer);

在您的情况下,这可能是可以忽略不计的,但值得为更大的迭代计数做。

如果您只对5个最低价格感兴趣,则无需对整个数组进行排序。

循环通过数组,同时保持5个最低价格的键列表。

我在PHP中太生疏了,无法有效地提供样本。

答案 5 :(得分:0)

我看到两个可能会减慢代码速度的区域:

  • 对数组进行排序
  • 回复+字符串连接所有这些字符串

我首先要找出导致滞后的区域。如果难以进行分析,则可以在代码中插入调试打印语句,每个语句都会打印当前时间。这将给您一个粗略的想法,代码区域占用大部分时间。类似的东西:

echo "Time at this point is " . date();

一旦我们得到了这些结果,我们就可以进一步优化。

答案 6 :(得分:0)

试试这个......

$arr_fli = array(0 => array('f_name'=> 'Flight1', 'price' => 2000),
                 1 => array('f_name'=> 'Flight1', 'price' => 5000),
                 3 => array('f_name'=> 'Flight1', 'price' => 7000),
                 4 => array('f_name'=> 'Flight1', 'price' => 4000),
                 5 => array('f_name'=> 'Flight1', 'price' => 6000),
                 6 => array('f_name'=> 'Flight1', 'price' => 800),
                 7 => array('f_name'=> 'Flight1', 'price' => 1000),
                 8 => array('f_name'=> 'Flight1', 'price' => 500)
            );
foreach($arr_fli as $key=>$flights) {
    $fl_price[$flights['price']] = $flights;
}
sort($fl_price);
$i = 0;
foreach($fl_price as $final) {
    $i++;
    print_r($final);
    echo '<br />';
    if($i==5) {
        break;
    }
}

答案 7 :(得分:0)

要理解的第一件事是代码的哪一部分需要很长时间才能执行。 快速而肮脏但简单的方法是使用您的记录器。 我假设您已经使用它来记录您希望在代码运行时保留的所有其他信息, 例如内存使用,光盘使用,用户请求,购买等等。

您的记录器可能是一个高度软化的工具(只需google for&#34; loggin framework&#34;或者喜欢) 或者像消息编写器一样简单到您的文件。 要快速入门,您可以使用类似的东西:

class Logger {
  private $_fileName;
  private $_lastTime;

  public function __construct ($fileName) {
    $this->_fileName = $fileName;
    $this->_lastTime = microtime(true);
  }

  public function logToFile ($message) {
    // open file for writing by appending your message to the end of the file
    $file = fopen($this->_fileName, 'a');
    fwrite($file, $message . "\n");
    fclose($file);
  }

  // optional for testing - see your logs quickly without bothering with files
  public function logToConsole($message) {
    echo $message;
  }

  // optional $message to add, e.g. about what happened in your code
  public function logTimePassed ($message = '') {
    $timePassed = microtime(true) - $this->_lastTime;
    //$this->logToConsole("Milliseconds Passed since last log: " . $timePassed . ", " . $message . "\n");
    $this->logToFile("Milliseconds Passed since last log: " . $timePassed . ", " . $message . "\n");
    // reset time
    $this->_lastTime = microtime(true);
  }
}

// before your code starts
$myLogFileName = 'my-logs'; // or whatever the name of the file to write in
$myLogger = new Logger($myLogFileName);

// ... your code goes ...

// after something interesting
$myLogger->logTimePassed(); // log time since last logging

// ... your code continues ...

// after something else, adding a message for your record
$myLogger->logTimePassed("after sorting my flight array"); 

现在,您可以查看代码并将记录器放在所有关键点之后 任何可能需要太长时间的事情。添加您的消息以了解发生了什么。 可能存在许多延误的地方。 通常在内存中完成的数组操作非常快。 但需要更多关注更耗时的操作,例如:

  • 文件读/写,目录访问
  • 数据库访问
  • HTTP请求

例如,http请求 - 您的echo是通过网络立即发送到浏览器的吗? 它们是否每次都在循环中发送? 如果是,你可能想避免它。 如其他答案所示,将它们保存到数组中, 或使用Output Buffering

进一步减少对服务器的http请求,您可以尝试添加更多功能 在客户端并使用ajax只检索服务器真正需要的内容。

也不要忘记隐藏的事情。 例如,我看到对象属性访问:

$flights_result->json_data

这个对象是如何实现的?它只在内存中吗?它是否需要外部服务? 如果是的话,那可能是你的罪魁祸首。然后你必须努力优化它。 通过缓存查询来减少查询数量,优化数据,这样您只需查询更改等。 所有这些都取决于您的应用程序的结构,可能与您的其余代码无关。 如果您需要任何帮助,您显然需要在您的问题中提供此信息。

基本上任何未完全在内存中完成的操作都可能导致延迟。 对于内存中的操作,除非您的数据量巨大或操作非常激烈, 它们的影响可能微不足道。 如果您有任何疑问,只需将您的记录器放在一起&#34;可疑&#34;地方。


现在,根据您的特定代码,它混合了所有类型的东西, 这样外部对象访问,数组值访问,数组排序, 回声输出,也许隐藏其他东西。 这使得甚至很难知道将时间记录器放在何处。

使用它更容易的是使用面向对象的方法 并遵循分离关注原则(谷歌就此而言)。 这样,您的对象及其方法将承担单一责任 您将很容易看到谁做了记录器的放置和放置。

我不能高度推荐the legendary book by "Uncle Bob"来了解更多信息。 我假设你的代码来自一个函数。根据鲍勃叔叔的说法:

  

功能的第一条规则是它们应该很小。第二个规则是它们应该小于那个。

  

功能应该做一件事。他们应该做得好。他们应该只做它。

将代码拆分为更多函数时,您必须为这些函数提供有意义的名称,这些名称可以极大地提高代码的可读性。毋庸置疑,所有不打算在课外使用的函数都应该是私有的,因此您可以通过继承轻松地重用您的类。


有很多事情可以做,但为了让你开始,这里有一些想法:

  • 将数据数组封装到一个对象中,方法只根据您的需要进行操作。这样的事情:

    class Itineraries {
      private $_itineraryArray;
    
      public function __construct(array $itineraryArray) {
        $this->_itineraryArray = $itineraryArray;
      }
    
      public function getNCheapest ($number) {
        $this->_sortByPrice();
        $result = array();
        for ($i=0; $i< $number; $i++) {
          $result[] = $this->_itineraryArray[$i];
        }
        return $result;
      }
    
      private function _sortByPrice() {
        $prices = $this->_getPriceArray();
        array_multisort($prices, SORT_ASC, $this->_itineraryArray);
      }
    
      private function _getPriceArray () {
        foreach ($this->_itineraryArray as $entry) {
          $this->_getPrice($entry);  
        }
      }
    
      private function _getPrice($entry) {
        return $entry['price']['totalAmount']; // or whatever it is
      }
    }
    
    //Then you instantiate your object:
    $myItineraries = new Itineraries($flights_result->json_data['response']['itineraries']); // or whatever
    

请注意,如果您的数组结构完全改变, 您只需要调整方法_getPrice 以及实例化对象的单行! 其余代码将保持不变!

这是模型 - 视图 - 控制器范例中模型层的一部分。 您可以在谷歌上查找大量信息。 该模型知道如何处理其数据,但对此一无所知 它们的来源,没有浏览器输出,没有http请求等。

  • 然后,负责生成用户输出的所有内容都会进入您的视图层或所谓的Presenter Layer, 你有其他对象处理它的地方。你的所有回声都会传到这里。 这样的事情:

    class Presenter {
      public function outputNCheapest ($myItineraries, $number) {
        $outputData = $myItineraries->getNCheapest ($number);
        echo $this->generateOutput($outputData);
      }
    
      private function _generateOutput($outputData) {
        $html = '';
        // your html string is generated
        return $html;
      }
    }
    

但是,我个人反对在服务器上生成HTML。 这只是浪费带宽和用户等待响应的时间。 每次我等待浏览器重新加载整个页面时,我都希望开发人员阅读此内容。 您可以输出JSON而不是HTML,并使用ajax或客户端的其他方式请求它。

此外,您的用户的浏览器可以缓存部分数据,而不是再次请求它们, 并决定要求什么。这将进一步减少用户的延迟, 在一天结束时,正是你所关心的。