views:

10430

answers:

9

I have CSV data loaded into a multidimensional array. In this way each "row" is a record and each "column" contains the same type of data. I am using the function below to load my CSV file.


function f_parse_csv($file, $longest, $delimiter)
  {
  $mdarray = array();
  $file    = fopen($file, "r");
  while ($line = fgetcsv($file, $longest, $delimiter))
    {
    array_push($mdarray, $line);
    }
  fclose($file);
  return $mdarray;
  }

I need to be able to specify a column to sort so that it rearranges the rows. One of the columns contains date information in the format of "Y-m-d H:i:s" and I would like to be able to sort with the most recent date being the first row.

+2  A: 

The "Usort" function is your answer. http://si.php.net/manual/en/function.usort.php

Jan Hancic
+12  A: 

With usort. Here's a generic solution, that you can use for different columns:

class TableSorter {
  protected $column;
  function __construct($column) {
    $this->column = $column;
  }
  function sort($table) {
    usort($table, array($this, 'compare'));
    return $table;
  }
  function compare($a, $b) {
    if ($a[$this->column] == $b[$this->column]) {
      return 0;
    }
    return ($a[$this->column] < $b[$this->column]) ? -1 : 1;
  }
}

To sort by first column:

$sorter = new TableSorter(0); // sort by first column
$mdarray = $sorter->sort($mdarray);
troelskn
I get Parse error: parse error, unexpected T_STRING, expecting T_OLD_FUNCTION or T_FUNCTION or T_VAR or '}' on the second line of that class.
Melikoth
this code requires php5
Devon
Replace "protrected" with "var" and "__construct" with "TableSorter", and it will work in PHP4. Notice however, that PHP4 is discontinued.
troelskn
I set PHP to v5, didn't know it was running v4 by default. Having looked at it for a while I think I understand how to modify it for different types of sorts as well
Melikoth
A: 

I prefer to use array_multisort http://us2.php.net/manual/en/function.array-multisort.php

Tim Boland
+9  A: 

You can use array_multisort()

Try something like this:

foreach ($mdarray as $key => $row) {
    $dates[$key]  = $row[0]; 
    // of course, replace 0 with whatever is the date field's index
}

array_multisort($dates, SORT_DESC, $mdarray);
Shinhan
I think this shows me why I couldn't get array_multisort to work before.
Melikoth
array_multisort() is the way I've always done it, though it can be a bit tricky to wrap your head around how it works at first.
Garrett Albright
This is a very good example for figuring that out.
Melikoth
So in this example, $mdarray might be a two-dimensional array, like an array of database records. In this example, 0 is the index of the 'date' column in each record (or row). So you construct the $dates array (basically the same array, but with only that column), and tell the array_multisort function to sort $mdarray based on that particular column's values.
Dan
For clarity, you might add to the beginning of this example `$dates = array();`
Dan
This answer really helped me in my current project, thanks!
Stephen
A: 

Here is a php4/php5 class that will sort one or more fields:

// a sorter class
//  php4 and php5 compatible
class Sorter {

  var $sort_fields;
  var $backwards = false;
  var $numeric = false;

  function sort() {
    $args = func_get_args();
    $array = $args[0];
    if (!$array) return array();
    $this->sort_fields = array_slice($args, 1);
    if (!$this->sort_fields) return $array();

    if ($this->numeric) {
      usort($array, array($this, 'numericCompare'));
    } else {
      usort($array, array($this, 'stringCompare'));
    }
    return $array;
  }

  function numericCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      if ($a[$sort_field] == $b[$sort_field]) {
        continue;
      }
      return ($a[$sort_field] < $b[$sort_field]) ? ($this->backwards ? 1 : -1) : ($this->backwards ? -1 : 1);
    }
    return 0;
  }

  function stringCompare($a, $b) {
    foreach($this->sort_fields as $sort_field) {
      $cmp_result = strcasecmp($a[$sort_field], $b[$sort_field]);
      if ($cmp_result == 0) continue;

      return ($this->backwards ? -$cmp_result : $cmp_result);
    }
    return 0;
  }
}

/////////////////////
// usage examples

// some starting data
$start_data = array(
  array('first_name' => 'John', 'last_name' => 'Smith', 'age' => 10),
  array('first_name' => 'Joe', 'last_name' => 'Smith', 'age' => 11),
  array('first_name' => 'Jake', 'last_name' => 'Xample', 'age' => 9),
);

// sort by last_name, then first_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort by first_name, then last_name
$sorter = new Sorter();
print_r($sorter->sort($start_data, 'first_name', 'last_name'));

// sort by last_name, then first_name (backwards)
$sorter = new Sorter();
$sorter->backwards = true;
print_r($sorter->sort($start_data, 'last_name', 'first_name'));

// sort numerically by age
$sorter = new Sorter();
$sorter->numeric = true;
print_r($sorter->sort($start_data, 'age'));
Devon
Does this only work with associative arrays?
Melikoth
yes - associative arrays only. Now that I look at it, it is not the right solution for this problem.
Devon
A: 

Before I could get the TableSorter class to run I had came up with a function based on what Shinhan had provided.

function sort2d_bycolumn($array, $column, $method, $has_header)
  {
  if ($has_header)  $header = array_shift($array);
  foreach ($array as $key => $row) {
    $narray[$key]  = $row[$column]; 
    }
  array_multisort($narray, $method, $array);
  if ($has_header) array_unshift($array, $header);
  return $array;
  }
  • $array is the MD Array you want to sort.
  • $column is the column you wish to sort by.
  • $method is how you want the sort performed, such as SORT_DESC
  • $has_header is set to true if the first row contains header values that you don't want sorted.
Melikoth
A: 

foreach ($array2sort as $key => $row) { $data[$key] = $row[0];

}

array_multisort($data, SORT_ASC, $array2sort);

exactly what Shinhan told... awesome ...

cheers

Mavendev
A: 

Hello,

I've made a generic Sorter class for sorting different values in arrays (simple arrays, 2D - multidimensional arrays, arrays of objects).

It is very easy to use. You can find out more at: http://blog.westrem.sk/2009/12/28/generic-sorting-solution-in-php/

Hope it helps ..

Jan Jadud
A: 

Here is my implementation. I had a category object which incorporated category entries. I wanted to sort those entries by a sub-array value. Here's how I went about it.

Where $in_cat_team_arr is the unsorted array

<?php
//sort multidimensional array by $order_in_category
if (count ($in_cat_team_arr) > 0) {
    foreach ($in_cat_team_arr as $key => $row) {
        $order_in_category[$key]  = $row[0];//[0] is $order_in_category
    }
    array_multisort($order_in_category, SORT_ASC, $in_cat_team_arr);
}

foreach ($in_cat_team_arr as $team_mem) {
    //loop through the sorted array here
}

This works nicely for me.

I do have a question though. Is there any way to use the key name rather than index (e.g. $row['my_key_name'] instead of $row[0])? I tried this and it got scrambled.

Aaron Newton