I have a number of text files each with 4 pieces of data on each line: name, date, time and comment.

I have used $fh to open and read the data and put them in 1 long variable called $AllComments.

I then need to sort them by date and time before I explode each line and display the data.

I am just having trouble sorting the variable called $AllComments

Any suggestions?

Many thanks, Patrick

Recommended Answers

All 6 Replies

an example of a single line would be:

Example name;3rd July 20010;21:08;Example of a comment;

(using ; to separate fields for exploding)

If you explode your $AllComments into an array, where each item is a line, then you would be able to use usort to sort it. The two items can be exploded in the compare function so you can check the date and time. Perhaps by merging them and converting them to a timestamp.

Here is what I have so far:

I am still unsure how to sort each line from the array '$messages' by $comment[3] and comment[4]

$messages = explode("\n", $AllComments);

  foreach ($messages as $comment){
        $comment = explode(";", $comment);

Have a look at example #2 from the link I gave. That should give you an idea. Also, look at strtotime() to convert the date and time to a timestamp, which will be easier to compare.

I'm going to assume you're using PHP 5...this will not work otherwise.

First off here is the test CSV file I used based on what you provided:
(test.csv)

Example name1;3rd July 2010;21:08;Example of a comment 1
Example name2;4th July 2010;22:08;Example of a comment 2
Example name3;4th July 2010;23:08;Example of a comment 3
Example name4;3rd July 2010;19:08;Example of a comment 4

Now my actual solution.

<?php

class SortingIterator implements IteratorAggregate
{

	private $iterator = null;


	public function __construct(Traversable $iterator, $callback)
	{
			if (!is_callable($callback)) {
					throw new InvalidArgumentException('Given callback is not callable!');
			}

			$array = iterator_to_array($iterator);
			usort($array, $callback);
			$this->iterator = new ArrayIterator($array);
	}


	public function getIterator()
	{
			return $this->iterator;
	}
}

function DateSort($a, $b)
{
	$aDateTime = new DateTime($a[1].' '.$a[2]);
	$bDateTime = new DateTime($b[1].' '.$b[2]);
	
	return $aDateTime->getTimestamp() > $bDateTime->getTimestamp();
}


$file = new SplFileObject('test.csv');
$file->setFlags(SplFileObject::READ_CSV);
$file->setCsvControl(';');

$it = new SortingIterator($file, 'DateSort');
foreach($it as $line){
	var_dump($line);
}

There are really three parts to this. I use the SplFileObject class from the SPL library to open the csv file and setup the class so it reads it as a csv and uses a semi-colon as the delimiter. (lines 34 - 36)

SplFileObject is an iterator for the lines of a file, basically it means you can do:

foreach($file as $line){
  var_dump($line);
}

and it will spit out info about each line of the file, in this case each is an array as we've told it to read each line as csv.

Then I created a SortingIterator based on (http://www.ruempler.eu/2008/08/09/php-sortingiterator/) which i've linked to before around here.

What the sorting iterator does is take the SplFileObject iterator reads it in, dumps it into an array and runs it through my callback function DateSort. Then creates a new iterator from it and returns it back. So it read the file, sorted all the lines, and then turned it back into an object we can easily iterate over and extend etc. The DateSort function simply takes the date and time parts and makes a single string and then compares them for timestamp values. The function returns true or false depending on whether $a is greater than $b or not.

You end up with a nice sorted result like this:

array
  0 => string 'Example name4' (length=13)
  1 => string '3rd July 2010' (length=13)
  2 => string '19:08' (length=5)
  3 => string 'Example of a comment 4' (length=22)
array
  0 => string 'Example name1' (length=13)
  1 => string '3rd July 2010' (length=13)
  2 => string '21:08' (length=5)
  3 => string 'Example of a comment 1' (length=22)
array
  0 => string 'Example name2' (length=13)
  1 => string '4th July 2010' (length=13)
  2 => string '22:08' (length=5)
  3 => string 'Example of a comment 2' (length=22)
array
  0 => string 'Example name3' (length=13)
  1 => string '4th July 2010' (length=13)
  2 => string '23:08' (length=5)
  3 => string 'Example of a comment 3' (length=22)

This seems like a lot to stomach, and it is especially if you're inexperienced. But what makes this such a nice solution is its re-usability.

There are a bunch of additional useful things you could do with this, like filtering stacking sorts etc. and I'll be more than happy to explain those if this all makes sense. Let me know if you need anything explained better or have any questions.

FYI. Here is another option. I built this quite a while back to sort a two-dimensional array on up to 6 keys (using the array_multisort command). This is a bit more than you need in this case but anyone who needs to sort records by one or more keys may find it useful.

You would need to load you data into an array so that records would look like:

$test['0']['name'] = "Example name 1";
	$test['0']['date'] = "3rd July 2010;21:08";
	$test['0']['comment'] = "Example of a comment 1";

________________________________________________________________________
Module: array_rows_to_columns.php
This sets up the data so array_multisort will work.

<?PHP
Function array_rows_to_columns (&$array_name, $field1="", $field2="", $field3="", $field4="", $field5="", $field6="") {

	// this changes the rows to columns (ie as separate arrays) so that multisort can sort them
	// This can be used when you have a multi-dimentsion array of the form:
	//	$test_array[key][field1], $test_array[key][field2] etc
	
	// when you want to be able to do a multisort on field1, field2 and so forth.
        // This can handle up to 6 fields that are to become new arrays and sort fields.
     
        // When these are sorted, the association between the fields is retained even though they are
       // in separate arrays.
     /*
     	Example use:
		array_rows_to_columns ($test,"last_name","first_name","address","phone");
 		$result = array_multisort($sort_field1,$sort_field2,$sort_field3,$sort_field4,$test);
 		
 		where: 	$test is the original array
				last_name, first_name etc are field names to sort by
				
		It sorts the original array so you can access the results there.

		You must use "foreach .. " to extract the data - see the examples 
	*/

	global $sort_field1, $sort_field2, $sort_field3, $sort_field4, $sort_field5, $sort_field6;
     
	// --- redefine the sort arrays to get rid of any previous content ---
	//  (unset didn't give the desired result in this case)
	$sort_field1 = array();
	$sort_field2 = array();
	$sort_field3 = array();
	$sort_field4 = array();
	$sort_field5 = array();
	$sort_field6 = array();

	foreach ($array_name as $key => $row) {

    		$sort_field1[$key]  		= $row[$field1];

		if ($field2 <> "") {
          	        $sort_field2[$key] 		= $row[$field2];
                }

		if ($field3 <> "") {
    			$sort_field3[$key]  	= $row[$field3];
    		}

		if ($field4 <> "") {
			$sort_field4[$key]		= $row[$field4];
		}

		if ($field5 <> "") {
			$sort_field5[$key]		= $row[$field5];
		}

		if ($field6 <> "") {
			$sort_field6[$key]		= $row[$field6];
		}
	}
}


?>

This example uses a different set of data but it's easy to see how this could be adapted to use your data:

<?PHP
/*
  	Demo of sorting (associative) arrays
  	
	This version uses all 4 fields as a sort key and it uses 
	a Function to convert rows to columns

*/

// ====== The Setup =========================================================================


	include "array_rows_to_columns.php";

	$test = array();

	// Note: key1, key2, key3 ... could just as well be an index number ( 0 - n).
	// It doesn't matter.
	$test['key1']['last_name'] = "Smith";
	$test['key1']['first_name'] = "John";
	$test['key1']['address'] = "123 Main";
	$test['key1']['phone'] = "905-123-1111";

	$test['key2']['last_name'] = "Smith";
	$test['key2']['first_name'] = "Al";
	$test['key2']['address'] = "555 Main";
	$test['key2']['phone'] = "905-123-1111";
	
	$test['key2a']['last_name'] = "Smith";          // same name as prev but with a different address and phone
	$test['key2a']['first_name'] = "Al";
	$test['key2a']['address'] = "111 Main";
	$test['key2a']['phone'] = "905-123-1999";

	$test['key3']['last_name'] = "Brown";
	$test['key3']['first_name'] = "Bob";
	$test['key3']['address'] = "234 Main";
	$test['key3']['phone'] = "905-123-2222";

	$test['key4']['last_name'] = "Jones";
	$test['key4']['first_name'] = "Mary";
	$test['key4']['address'] = "456 Main";
	$test['key4']['phone'] = "905-123-3333";

	$test['key5']['last_name'] = "Green";
	$test['key5']['first_name'] = "Harry";
	$test['key5']['address'] = "666 Main";
	$test['key5']['phone'] = "905-123-4444";
	
	$test['key6']['last_name'] = "Brown";
	$test['key6']['first_name'] = "Maury";
	$test['key6']['address'] = "234 Main";
	$test['key6']['phone'] = "905-123-2222";



// ======== Now we can sort ================================================================

	array_rows_to_columns ($test,"last_name","first_name","address","phone");

     // this creates arrays called sort_field1, sort_field2...
	// The working arrays are used in the multisort followed by the original array
	$result = array_multisort($sort_field1,$sort_field2,$sort_field3,$sort_field4,$test); // the original array is included last

	if ($result == false) {
		echo "<br><b>Sort Error </b>";
	}

// ======== Now we print the sorted result =================================================

	echo "<b><font size=4 color=blue>Array Sorting Demo </font></b>";
	echo "<br><br><i>The array has been sorted on last_name, first_name, address and phone.
		<br>The records started out in the order key1, key2, key2a etc.
		</i><br><br>";

	// you must use foreach to extract the info by key.
	foreach ($test as $key => $details) {
	
	  echo "<br>($key) &nbsp;&nbsp;";
          echo $details['first_name'];
	  echo " ".$details['last_name'];
          echo " &nbsp;&nbsp;".$details['address'];
	  echo " &nbsp;&nbsp;".$details['phone'];
	}
	

?>
Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.