sort.php 4.69 KB
Newer Older
Scott committed
1 2 3 4 5
<?php
/*
	Question2Answer by Gideon Greenspan and contributors
	http://www.question2answer.org/

Scott committed
6
	File: qa-include/util/sort.php
Scott committed
7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
	Description: A useful general-purpose 'sort by' function


	This program is free software; you can redistribute it and/or
	modify it under the terms of the GNU General Public License
	as published by the Free Software Foundation; either version 2
	of the License, or (at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	More about this license: http://www.question2answer.org/license.php
*/

	if (!defined('QA_VERSION')) { // don't allow this page to be requested directly from browser
		header('Location: ../');
		exit;
	}


	function qa_sort_by(&$array, $by1, $by2=null)
/*
	Sort the $array of inner arrays by sub-element $by1 of each inner array, and optionally then by sub-element $by2
*/
	{
		global $qa_sort_by_1, $qa_sort_by_2;

		$qa_sort_by_1=$by1;
		$qa_sort_by_2=$by2;

		uasort($array, 'qa_sort_by_fn');
	}


	function qa_sort_by_fn($a, $b)
/*
	Function used in uasort to implement qa_sort_by()
*/
	{
		global $qa_sort_by_1, $qa_sort_by_2;

		$compare=qa_sort_cmp($a[$qa_sort_by_1], $b[$qa_sort_by_1]);

		if (($compare==0) && $qa_sort_by_2)
			$compare=qa_sort_cmp($a[$qa_sort_by_2], $b[$qa_sort_by_2]);

		return $compare;
	}


	function qa_sort_cmp($a, $b)
/*
	General comparison function for two values, textual or numeric
*/
	{
		if (is_numeric($a) && is_numeric($b)) // straight subtraction won't work for floating bits
			return ($a==$b) ? 0 : (($a<$b) ? -1 : 1);
		else
			return strcasecmp($a, $b); // doesn't do UTF-8 right but it will do for now
	}


	function qa_array_insert(&$array, $beforekey, $addelements)
/*
	Inserts $addelements into $array, preserving their keys, before $beforekey in that array.
	If $beforekey cannot be found, the elements are appended at the end of the array.
*/
	{
		$newarray=array();
		$beforefound=false;

		foreach ($array as $key => $element) {
			if ($key==$beforekey) {
				$beforefound=true;

				foreach ($addelements as $addkey => $addelement)
					$newarray[$addkey]=$addelement;
			}

			$newarray[$key]=$element;
		}

		if (!$beforefound)
			foreach ($addelements as $addkey => $addelement)
				$newarray[$addkey]=$addelement;

		$array=$newarray;
	}


//	Special values for the $beforekey parameter for qa_array_reorder() - use floats since these cannot be real keys

	define('QA_ARRAY_WITH_FIRST', null); // collect the elements together in the position of the first one found
	define('QA_ARRAY_WITH_LAST', 0.6); // collect the elements together in the position of the last one found
	define('QA_ARRAY_AT_START', 0.1); // place all the elements at the start of the array
	define('QA_ARRAY_AT_END', 0.9); // place all the elements at the end of the array

	function qa_array_reorder(&$array, $keys, $beforekey=null, $reorderrelative=true)
/*
	Moves all of the elements in $array whose keys are in the parameter $keys. They can be moved to before a specific
	element by passing the key of that element in $beforekey (if $beforekey is not found, the elements are moved to the
	end of the array). Any of the QA_ARRAY_* values defined above can also be passed in the $beforekey parameter.
	If $reorderrelative is true, the relative ordering between the elements will also be set by the order in $keys.
*/
	{

	//	Make a map for checking each key in $array against $keys and which gives their ordering

		$keyorder=array();
		$keyindex=0;
		foreach ($keys as $key)
			$keyorder[$key]=++$keyindex;

	//	Create the new key ordering in $newkeys

		$newkeys=array();
		$insertkeys=array();
		$offset=null;

		if ($beforekey==QA_ARRAY_AT_START)
			$offset=0;

		foreach ($array as $key => $value) {
			if ($beforekey==$key)
				$offset=count($newkeys);

			if (isset($keyorder[$key])) {
				if ($reorderrelative)
					$insertkeys[$keyorder[$key]]=$key; // in order of $keys parameter
				else
					$insertkeys[]=$key; // in order of original array

				if ( ($beforekey==QA_ARRAY_WITH_LAST) || (($beforekey===QA_ARRAY_WITH_FIRST) && !isset($offset)) )
					$offset=count($newkeys);

			} else
				$newkeys[]=$key;
		}

		if (!isset($offset)) // also good for QA_ARRAY_AT_END
			$offset=count($newkeys);

		if ($reorderrelative)
			ksort($insertkeys, SORT_NUMERIC); // sort them based on position in $keys parameter

		array_splice($newkeys, $offset, 0, $insertkeys);

	//	Rebuild the array based on the new key ordering

		$newarray=array();

		foreach ($newkeys as $key)
			$newarray[$key]=$array[$key];

		$array=$newarray;
	}


/*
	Omit PHP closing tag to help avoid accidental output
Gideon Greenspan committed
169
*/