qa-util-sort.php 4.9 KB
Newer Older
Gideon Greenspan committed
1 2 3 4 5 6 7
<?php

/*
	Question2Answer (c) Gideon Greenspan

	http://www.question2answer.org/

Scott Vivian committed
8

Gideon Greenspan committed
9 10 11 12 13 14 15 16 17
	File: qa-include/qa-util-sort.php
	Version: See define()s at top of qa-include/qa-base.php
	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.
Scott Vivian committed
18

Gideon Greenspan committed
19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38
	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;
Scott Vivian committed
39

Gideon Greenspan committed
40 41
		$qa_sort_by_1=$by1;
		$qa_sort_by_2=$by2;
Scott Vivian committed
42

Gideon Greenspan committed
43 44 45 46 47 48 49 50 51 52
		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;
Scott Vivian committed
53

Gideon Greenspan committed
54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
		$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);
Gideon Greenspan committed
70
		else
Gideon Greenspan committed
71 72
			return strcasecmp($a, $b); // doesn't do UTF-8 right but it will do for now
	}
Scott Vivian committed
73 74


Gideon Greenspan committed
75 76 77 78 79 80 81 82
	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;
Scott Vivian committed
83

Gideon Greenspan committed
84 85 86
		foreach ($array as $key => $element) {
			if ($key==$beforekey) {
				$beforefound=true;
Scott Vivian committed
87

Gideon Greenspan committed
88 89 90
				foreach ($addelements as $addkey => $addelement)
					$newarray[$addkey]=$addelement;
			}
Scott Vivian committed
91

Gideon Greenspan committed
92 93
			$newarray[$key]=$element;
		}
Scott Vivian committed
94

Gideon Greenspan committed
95 96 97
		if (!$beforefound)
			foreach ($addelements as $addkey => $addelement)
				$newarray[$addkey]=$addelement;
Scott Vivian committed
98

Gideon Greenspan committed
99 100
		$array=$newarray;
	}
Scott Vivian committed
101 102


Gideon Greenspan committed
103 104 105 106 107 108
//	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
Scott Vivian committed
109

Gideon Greenspan committed
110 111 112 113 114 115 116 117 118 119
	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
Scott Vivian committed
120

Gideon Greenspan committed
121 122 123 124
		$keyorder=array();
		$keyindex=0;
		foreach ($keys as $key)
			$keyorder[$key]=++$keyindex;
Scott Vivian committed
125

Gideon Greenspan committed
126
	//	Create the new key ordering in $newkeys
Scott Vivian committed
127

Gideon Greenspan committed
128 129 130
		$newkeys=array();
		$insertkeys=array();
		$offset=null;
Scott Vivian committed
131

Gideon Greenspan committed
132 133
		if ($beforekey==QA_ARRAY_AT_START)
			$offset=0;
Scott Vivian committed
134

Gideon Greenspan committed
135 136 137
		foreach ($array as $key => $value) {
			if ($beforekey==$key)
				$offset=count($newkeys);
Scott Vivian committed
138

Gideon Greenspan committed
139 140 141 142 143
			if (isset($keyorder[$key])) {
				if ($reorderrelative)
					$insertkeys[$keyorder[$key]]=$key; // in order of $keys parameter
				else
					$insertkeys[]=$key; // in order of original array
Scott Vivian committed
144

Gideon Greenspan committed
145 146
				if ( ($beforekey==QA_ARRAY_WITH_LAST) || (($beforekey===QA_ARRAY_WITH_FIRST) && !isset($offset)) )
					$offset=count($newkeys);
Scott Vivian committed
147

Gideon Greenspan committed
148 149 150
			} else
				$newkeys[]=$key;
		}
Scott Vivian committed
151

Gideon Greenspan committed
152 153
		if (!isset($offset)) // also good for QA_ARRAY_AT_END
			$offset=count($newkeys);
Scott Vivian committed
154

Gideon Greenspan committed
155 156
		if ($reorderrelative)
			ksort($insertkeys, SORT_NUMERIC); // sort them based on position in $keys parameter
Scott Vivian committed
157

Gideon Greenspan committed
158
		array_splice($newkeys, $offset, 0, $insertkeys);
Scott Vivian committed
159

Gideon Greenspan committed
160
	//	Rebuild the array based on the new key ordering
Scott Vivian committed
161

Gideon Greenspan committed
162
		$newarray=array();
Scott Vivian committed
163

Gideon Greenspan committed
164 165
		foreach ($newkeys as $key)
			$newarray[$key]=$array[$key];
Scott Vivian committed
166

Gideon Greenspan committed
167 168
		$array=$newarray;
	}
Scott Vivian committed
169

Gideon Greenspan committed
170 171 172 173

/*
	Omit PHP closing tag to help avoid accidental output
*/