8

I have array which contains info about many flights. I want only the five lowest prices.

First I make a loop to sort array by price.

Second I print first five array

But it takes more time..How can I reduce this time?

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 example

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
                )

        )

)

2
  • Instead of echoing/printing from inside the loop, you should write strings to a buffer, then echo/print it after the loop. Commented Sep 26, 2013 at 16:39
  • can you give me example? Commented Sep 26, 2013 at 16:41

8 Answers 8

4
+50

To answer your questions:

but it take more time..how to reduce this big time?

Before you can reduce that you need to find out exactly where that more comes from. As you wrote in a comment, you are using a remote request to obtain the data.

Sorting for array the data you've provided works extremely fast, so I would assume you don't need to optimize the array sorting but just the way when and how you get the data from remote. One way to do so is to cache that or to prefetch it or to do parallel processing. But the details so far are not important at all, unless you've found out where that more comes from so that it is clear what is responsible for big time so then it can be looked into reducing it.

Hope this is helpful so far, and feel free to add the missing information to your question.

You can see the array-only code in action here, it's really fast:

You can find the execution stats just below the output, exemplary from there:

OK (0.008 sec real, 0.006 sec wall, 14 MB, 99 syscalls)

Sign up to request clarification or add additional context in comments.

Comments

2

You should really install a profiler (XHProf) and check what exactly takes so much time.

I assume it is the sorting, because foreach through the final array of 5 elements should be lighning fast. Why do you sort it then? If the sole purpose of sorting is to find 5 "lowest" items, then the fastest way would be to just find 5 lowest items:

$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

It will find 5 items with about O(6n) which in your case should better than potential O(n²) with sorting; Then you may just use it like:

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

This should be a lot faster, provided it was the sorting! so get that XHprof and check :)

6 Comments

adam where i put the printing to the values?
In the last loop I provided in my answer :) also be sure to check if this webservice allows you to sort your data, maybe you don't need that magic at all
when i try print_r after sort it take many time and the result like this
Array ( [351] => [220] => 579.00 [221] => 579.00 [222] => 584.00 [223] => 584.00 )
print $minValue or $intinerary ?
|
1

Here's what I would have done:

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

It's either that or write a recursive function to go through all the data. Also note, this only works if your data is in the order you want.

2 Comments

after add your code the result is carrier name: carrier code: --------
Missed the space in ' carrier', got it now.
0

I would do the following things:

// 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
     ...
}

2 Comments

where i put the count to stop loop after 5 loops
You can either get the keys from mid and just use the first five (either with a for loop or the built-in PHP function array_slice). Or you could add a counter that starts at 0 and have the loop end (via a break) when the counter was equal to 4. (or 5 if you start at 1)
0

Buffer echo/print (ie, do not echo/print from inside loop):

$buffer = "";

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

print($buffer);

This is probably negligable in your case, but worth doing for larger iteration counts.

You don't need to sort the entire array if you're only interested in the 5 lowest prices.

Loop through the array while maintaining a list of the keys with the 5 lowest prices.

I'm too rusty in PHP to effectively provide a sample.

Comments

0

I see two potential areas slowing down the code:

  • Sorting the array
  • Echoing + string concatenating all those strings

I would first find out which area is causing the lag. If profiling is difficult, you can insert debugging print statements into your code with each statement print the current time. This will give you a rough idea, which area of code is taking bulk of the time. Something like:

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

Once we have those results we can optimize further.

Comments

0

Try this...

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

Comments

0

The first thing to understand is which part of you code takes long to execute. A quick and dirty but simple way is to use your logger. Which I assume you are using already to log all your other information you want to keep as your code runs, such as memory usage, disc usage, user requests, purchases made etc.

Your logger can be a highly sofisticated tool (just google for "loggin framework" or the likes) or as simple as message writer to your file. To get a quick start, you can using something like that:

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

Now you can go over your code and place your loggers at all crucial points after anything that may potentially take too long. Add your messages to know what happened. There can potentially be many places for delays. Usually array manipulations done in-memory are blazing fast. But more attention needs to be paid for more time consuming operations such as:

  • File reading/ writing, directory access
  • Database access
  • HTTP requests

For instance, http requests - are your echos being sent immediately to browser over a network? Are they being sent every time in the loop? If yes, you probably want to avoid it. Either save them into array as indicated by other answers, or use Output Buffering.

Further to minimize http requests to your server, you can try to put more functions on the client side and use ajax to only retrieve what is really needed from the server.

Also don't forget about things that are hidden. For instance, I see object property access:

$flights_result->json_data

How is this object implemented? Is it in-memory only? Does it call to outside services? If yes, that may be your culprit. Then you have to work on optimizing that. Reducing the number of queries by caching them, optimizing your data so you only need to query the changes, etc. All this depends on the structure of you application and may have nothing to do with the rest of your code. If you want any help on that, you obviously need to put this information in your question.

Basically anything that is not done entirely in memory can cause delays. As for the in-memory operations, unless your data are huge or your operations are intense, their effect will likely be negligible. Still if you have any doubt, simply place your loggers at all "suspicious" places.


Now to your specific code, it mixes all sort of things, such that outside object access, array value access, array sorting, echo outputs, maybe other things that are hidden. This makes it hard even to know where to place your time loggers.

What would make it much easier, is to use object oriented approach and follow, among others, the Principle of Separating Concerns (google on that). That way your objects and their methods will have single responsibilities and you will easily see who does what and where to place your loggers.

I can't highly enough recommend the legendary book by "Uncle Bob" to learn more about it. I presume your code comes from inside a function. According to Uncle Bob:

The first rule of functions is that they should be small. The second rule is that they should be smaller than that.

and

Functions should do one thing. They should do it well. They should do it only.

When splitting your code into more functions, you are forced to give those functions meaningful names that can greatly improve readability of your code. Needless to say, all functions not intended for use outside the class, should be private, so you can easily re-use your classes via inheritance.


There is a lot that can be done, but just to get you started, here are some ideas:

  • Encapsulate your data array into an object with methods only doing there what you need. Something like that:

    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
    

Notice that should your array structure completely change, you'll only need to adjust the method _getPrice and the single line to instantiate your object! The rest of your code will remain intact!

This is a part of your Model Layer in the Model-View-Controller paradigm. You can google on that to find lots of information. The model knows how to handle its data but knows nothing about the source of them, no browser output, no http requests etc.

  • Then everything responsible for generating user output goes into your View Layer or into so-called Presenter Layer, where you have other objects dealing with it. All your 'echo's will go here. Something like that:

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

However, I am personally against generating HTML on the server. It is just a waste of bandwidth and the time of your users waiting for response. Every time I am waiting for my browser to reload the whole page, I want the developer to read this. You can output JSON instead of HTML and request it with ajax or via other ways on the client side.

Furthermore, your user's browser can cache some of the data instead of requesting them again, and decide what to ask for. That will further minimize the delay for your users, which at the end of the day is precisely what you are concerned with.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.