RSI helpers  0.1
RSI helpers
Record.php
Go to the documentation of this file.
1 <?php
2 
3 namespace Rsi;
4 
5 /**
6  * Record (array) helpers.
7  */
8 class Record{
9 
10  /**
11  * Enhanced explode.
12  * @param mixed $array Value to turn into an array.
13  * @param string $delimiter Delimiter in case of a string.
14  * @param string $separator Key-value separator.
15  * @return array
16  */
17  public static function explode($array,$delimiter = null,$separator = null){
18  if(is_array($array)) return $array;
19  if($array === null) return [];
20  if(!$delimiter || !is_string($array)) return [$array];
21  $result = [];
22  if($array) foreach(explode($delimiter,$array) as $value){
23  if($separator){
24  $data = explode($separator,$value,2);
25  $value = array_pop($data);
26  $key = array_shift($data);
27  }
28  else $key = count($result);
29  $result[$key] = $value;
30  }
31  return $result;
32  }
33  /**
34  * Enhanced implode.
35  * @param mixed $array Array to turn into a string
36  * @param string $delimiter Delimiter.
37  * @param string $separator Key-value separator.
38  * @return string
39  */
40  public static function implode($array,$delimiter = null,$separator = null){
41  if(!is_array($array)) return $array;
42  if($separator) foreach($array as $key => &$value) $value = $key . $separator . $value;
43  unset($value);
44  return implode($delimiter,$array);
45  }
46  /**
47  * Checks if a key exists in an array.
48  * @param array $array Array to look in.
49  * @param string|array $key Key to look at. An array indicates a nested key. If the array is ['foo' => ['bar' => 'acme']],
50  * then the nested key for the 'acme' value will be ['foo','bar'].
51  * @return bool True if the key exists.
52  */
53  public static function exists($array,$key){
54  if(!is_array($key)) $key = [$key];
55  elseif(!$key) return false;
56  while($key){
57  if(!is_array($array) || !array_key_exists($sub = array_shift($key),$array)) return false;
58  $array = $array[$sub];
59  }
60  return true;
61  }
62  /**
63  * Get a value from an array.
64  * @param array $array Array to look in.
65  * @param string|array $key Key to look at. An array indicates a nested key. If the array is ['foo' => ['bar' => 'acme']],
66  * then the nested key for the 'acme' value will be ['foo','bar'].
67  * @param mixed $default Default value if the key does not exist.
68  * @return mixed Found value, or default value if the key does not exist.
69  */
70  public static function get($array,$key,$default = null){
71  if(!$array || !is_array($array)) return $default;
72  if(!is_array($key)) return array_key_exists($key,$array) ? $array[$key] : $default;
73  while($key) if(!array_key_exists($sub = array_shift($key),$array) || (!is_array($array = $array[$sub]) && $key)) return $default;
74  return $array;
75  }
76  /**
77  * Get a value from an array in a case insensitive way.
78  * @see get()
79  * @param array $array Array to look in.
80  * @param string|array $key Key to look at (case insensitive). An array indicates a nested key. If the array is
81  * ['foo' => ['bar' => 'acme']], then the nested key for the 'acme' value will be ['foo','bar'].
82  * @param mixed $default Default value if the key does not exist.
83  * @return mixed Found value, or default value if the key does not exist.
84  */
85  public static function iget($array,$key,$default = null){
86  if(!is_array($key)) $key = [$key];
87  elseif(!$key) return $default;
88  while($key){
89  if(!is_array($array)) return $default;
90  if(!array_key_exists($sub = array_shift($key),$array)){
91  $found = false;
92  foreach($array as $index => $value) if($found = !strcasecmp($index,$sub)){
93  $sub = $index;
94  break;
95  }
96  if(!$found) return $default;
97  }
98  $array = $array[$sub];
99  }
100  return $array;
101  }
102  /**
103  * Set a value of an array.
104  * If the key does not exist it will be created. With a nested key, sub-array will also be created.
105  * @param array $array Array to store the value in.
106  * @param string|array $key Key to store the value at. An array indicates a nested key. If the array is
107  * ['foo' => ['bar' => 'acme']], then the nested key for the 'acme' value will be ['foo','bar'].
108  * @param mixed $value
109  */
110  public static function set(&$array,$key,$value){
111  if(is_array($keys = $key)) $key = array_shift($keys);
112  else $keys = null;
113  if($keys){
114  if(!array_key_exists($key,$array)) $array[$key] = [];
115  self::set($array[$key],$keys,$value);
116  }
117  else $array[$key] = $value;
118  }
119  /**
120  * Add a value to an array if the key does not already exist.
121  * @param array $array Array to store the value in.
122  * @param string|array $key Key to store the value at. An array indicates a nested key. If the array is
123  * ['foo' => ['bar' => 'acme']], then the nested key for the 'acme' value will be ['foo','bar'].
124  * @param mixed $value
125  */
126  public static function add(&$array,$key,$value = null){
127  if(is_array($keys = $key)) $key = array_shift($keys);
128  else $keys = null;
129  if(!array_key_exists($key,$array)) $array[$key] = $keys ? [] : $value;
130  if($keys) self::add($array[$key],$keys,$value);
131  }
132  /**
133  * Delete a (nested) key from an array.
134  * @param array $array Array to delete the key from.
135  * @param string|array $key Key to delete. An array indicates a nested key.
136  */
137  public static function delete(&$array,$key){
138  if(is_array($keys = $key)){
139  $key = array_pop($keys);
140  foreach($keys as $sub)
141  if(array_key_exists($sub,$array)) $array = &$array[$sub];
142  else return false;
143  }
144  unset($array[$key]);
145  }
146  /**
147  * Flattens a multi-dimensional array.
148  * @param array $array Array to flatten.
149  * @param string $key_glue Key to combine the keys with (sequential, numerical keys if empty).
150  * @param string $key_prefix Prefix for the key.
151  * @return array One dimensional array.
152  */
153  public static function flatten($array,$key_glue = null,$key_prefix = null){
154  $result = [];
155  foreach($array as $key => $value)
156  if(is_array($value)) $result = array_merge($result,self::flatten($value,$key_glue,$key_prefix . $key . $key_glue));
157  else $result[$key_glue ? $key_prefix . $key : count($result)] = $value;
158  return $result;
159  }
160  /**
161  * Brings a flattend array back to its multi-dimensional form.
162  * @param array $array One dimensional array.
163  * @param string $key_glue Glue with which the keys are combined.
164  * @return array Multi-dimensional array.
165  */
166  public static function expand($array,$key_glue){
167  $result = [];
168  foreach($array as $key => $value) self::set($result,explode($key_glue,$key),$value);
169  return $result;
170  }
171  /**
172  * Get the n-th value from an array.
173  * @param array $array Array to get value from.
174  * @param int $index Value index (negative = start from end).
175  * @param mixed $default Default value if the index does not exist.
176  * @return mixed
177  */
178  public static function value($array,$index = 0,$default = null){
179  return self::get(array_values($array),$index + ($index < 0 ? count($array) : 0),$default);
180  }
181  /**
182  * Get the n-th key from an array.
183  * @param array $array Array to get key from.
184  * @param int $index Key index (negative = start from end).
185  * @return mixed Found key, false if not existing.
186  */
187  public static function key($array,$index = 0){
188  return self::get(array_keys($array),$index + ($index < 0 ? count($array) : 0),false);
189  }
190  /**
191  * Determine if an array is associative (that is, no ascending numerical key).
192  * @param array $array
193  * @return bool True if the array is associative.
194  */
195  public static function assoc($array){
196  return array_values($array) !== $array;
197  }
198  /**
199  * Splice with keys.
200  * @param array $array Input array.
201  * @param int $offset Where to start (negative = from end).
202  * @param int $length Length of part to remove.
203  * @param array $replace Array to replace removed part with.
204  * @return array
205  */
206  public static function splice($array,$offset,$length = 0,$replace = null){
207  if($offset < 0) $offset += count($array);
208  return array_merge(array_slice($array,0,$offset),$replace ?: [],array_slice($array,$offset + $length));
209  }
210  /**
211  * Merge arrays while preserving (duplicate) key sequence.
212  * E.g. ['a' => 5,'b' => 7,'d' => 3] + ['b' => 4,'c' => 2,'d' => 1] returns ['a' => 5,'b' => 4,'c' => 2,'d' => 1].
213  * @param array $arrays,... input array(s).
214  * @return array
215  */
216  public static function merge(...$arrays){
217  $result = [];
218  foreach($arrays as $array) if($result){
219  $insert = count($keys = array_keys($result));
220  foreach($keys as $index => $key) if(array_key_exists($key,$array)){
221  $insert = $index;
222  break;
223  }
224  foreach($array as $key => $value) if(in_array($key,$keys)){
225  $result[$key] = $value;
226  $insert = array_search($key,array_keys($result)) + 1;
227  }
228  else $result = self::splice($result,$insert++,0,[$key => $value]);
229  }
230  else $result = $array;
231  return $result;
232  }
233  /**
234  * Set the length of an array.
235  * @param array $array Input array.
236  * @param int $length Desired length.
237  * @param mixed $filler Value for new possible entries.
238  * @return array Input array with its length chopped or extended.
239  */
240  public static function resize($array,$length,$filler = null){
241  return array_slice(array_pad($array,$length,$filler),0,$length);
242  }
243  /**
244  * Creates an array by using one array for keys and another for its values.
245  * Basicly PHP's array_combine, but then without the same length restriction.
246  * @param array $keys Array of keys.
247  * @param array $values Array of values.
248  * @param mixed $filler Filler to use if array of values is shorter than keys.
249  * @return array Combined array.
250  */
251  public static function combine($keys,$values,$filler = null){
252  return array_combine($keys,self::resize($values,count($keys),$filler));
253  }
254  /**
255  * Searches the array for a given value and returns the first corresponding key if successful.
256  * Basicly PHP's array_search, but case insensitive.
257  * @param array $array Array with values.
258  * @param mixed $value Value to look for.
259  * @return mixed Key if found, otherwise false.
260  */
261  public static function isearch($array,$value){
262  if(($key = array_search($value,$array)) !== false) return $key;
263  $value = mb_strtolower($value);
264  foreach($array as $key => $sub) if(mb_strtolower($sub) == $value) return $key;
265  return false;
266  }
267  /**
268  * Add a prefix to all members of an array.
269  * @param array $array Array with values.
270  * @param string $prefix Prefix to add.
271  * @return array Prefixed array.
272  */
273  public static function prefix($array,$prefix){
274  foreach($array as &$value) $value = $prefix . $value;
275  unset($value);
276  return $array;
277  }
278  /**
279  * Add a prefix to all keys of an array.
280  * @param array $array Array with values.
281  * @param string $prefix Prefix to add.
282  * @return array Prefixed array.
283  */
284  public static function prefixKey($array,$prefix){
285  $result = [];
286  foreach($array as $key => $value) $result[$prefix . $key] = $value;
287  return $result;
288  }
289  /**
290  * Change the keys of an array.
291  * @param array $array Source array.
292  * @param array $keys Key = old key, value = new key.
293  * @param bool $keep If true, entries in the source array for which there is nog new key defined, will be kept in the result
294  * (with their original key).
295  */
296  public static function changeKey($array,$keys,$keep = true){
297  $result = [];
298  foreach($array as $key => $value)
299  if(array_key_exists($key,$keys)) $result[$keys[$key]] = $value;
300  elseif($keep) $result[$key] = $value;
301  return $result;
302  }
303  /**
304  * Merge the key and value of an assoc.array into a record.
305  * @param array $array Assoc.array.
306  * @param string $key_name Name under which the key is added to the record. If empty the key is not added.
307  * @param string $value_name Name under which the value is added to the record. If empty, and the value is an array, this
308  * array is merged with the record. Otherwise the value is not added.
309  * @return array Array of records (key is preserved).
310  */
311  public static function mergeKey($array,$key_name = null,$value_name = null){
312  $result = [];
313  foreach($array as $key => $value){
314  $record = [];
315  if($key_name) $record[$key_name] = $key;
316  if($value_name) $record[$value_name] = $value;
317  elseif(is_array($value)) $record += $value;
318  $result[$key] = $record;
319  }
320  return $result;
321  }
322  /**
323  * Return the values from a single column in the input array.
324  * Basicly PHP's array_column, but then retaining key association.
325  * @param array $array A multi-dimensional array (record set) from which to pull a column of values.
326  * @param string $column The column of values to return.
327  * @return array Returns an array of values representing a single column from the input array.
328  */
329  public static function column($array,$column){
330  $result = [];
331  foreach($array as $key => $record) $result[$key] = self::get($record,$column);
332  return $result;
333  }
334  /**
335  * Group records by a column.
336  * @param array $array A multi-dimensional array (record set).
337  * @param string $column The column to group by.
338  * @return array Records (value; maintaining key association) grouped by column (key).
339  */
340  public static function group($array,$column){
341  $result = [];
342  foreach($array as $key => $record){
343  if(!array_key_exists($group = self::get($record,$column),$result)) $result[$group] = [];
344  $result[$group][$key] = $record;
345  }
346  return $result;
347  }
348  /**
349  * Shuffle an array.
350  * Basicly PHP's shuffle, but then retaining key association (and not altering the input array).
351  * @param array $array Input array.
352  * @return array Shuffled array.
353  */
354  public static function shuffle($array){
355  $result = [];
356  $keys = array_keys($array);
357  shuffle($keys);
358  foreach($keys as $key) $result[$key] = $array[$key];
359  return $result;
360  }
361  /**
362  * Calculate the average of an array.
363  * @param array $array Array with numerical values.
364  * @return float Average value (false on empty array).
365  */
366  public static function average($array){
367  return ($count = count($array)) ? array_sum($array) / $count : false;
368  }
369  /**
370  * Calculate the mean average deviation of an array.
371  * @param array $array Array with numerical values.
372  * @param float $average Avarage value of array.
373  * @return float Mean average deviation (false on empty array).
374  */
375  public static function deviation($array, &$average = null){
376  $average = self::average($array);
377  $total = 0;
378  foreach($array as $value) $total += pow($value - $average,2);
379  return $array ? sqrt($total / count($array)) : false;
380  }
381  /**
382  * Return specific keys from an array.
383  * @param array $array Array to select from.
384  * @param array $keys Keys to select.
385  * @return array
386  */
387  public static function select($array,$keys){
388  $result = [];
389  foreach($array as $key => $value) if(in_array($key,$keys)) $result[$key] = $value;
390  return $result;
391  }
392  /**
393  * Sort an array.
394  * @param array $array Array to sort.
395  * @param callable|int $options Callback function for sorting or sorting flags.
396  * @param bool $key Sort by key.
397  * @return array Sorted array.
398  */
399  public static function sort($array,$options = null,$key = false){
400  if(is_callable($options)){
401  if($key) uksort($array,$options);
402  else uasort($array,$options);
403  }
404  else{
405  if($key) ksort($array,$options);
406  else asort($array,$options);
407  }
408  return $array;
409  }
410  /**
411  * Retrieve numerical ranges from an array.
412  * @param array $array Array with numbers.
413  * @return array Key = start of range, value = end of range.
414  */
415  public static function ranges($array){
416  $result = [];
417  if($array){
418  sort($array);
419  $previous = $start = array_shift($array);
420  while($array){
421  $current = array_shift($array);
422  if($current > $previous + 1){
423  $result[$start] = $previous;
424  $start = $current;
425  }
426  $previous = $current;
427  }
428  $result[$start] = $previous;
429  }
430  return $result;
431  }
432  /**
433  * Group a list of strings by its first letter(s).
434  * @param array $array Array with strings.
435  * @param int $length Number of characters to group by.
436  * @param bool $case_sensitive Use case sensitivity for grouping.
437  * @return array Key = letter(s), value = array with strings (and keys).
438  */
439  public static function groupByLetter($array,$length = 1,$case_sensitive = false){
440  $result = [];
441  foreach($array as $key => $value){
442  $letter = substr($value,0,$length);
443  if(!$case_sensitive) $letter = mb_convert_case($letter,MB_CASE_UPPER);
444  if(!array_key_exists($letter,$result)) $result[$letter] = [];
445  $result[$letter][$key] = $value;
446  }
447  return $result;
448  }
449  /**
450  * Group a list of strings by its most common start.
451  * @param array $array Array with strings.
452  * @param int $max Maximum number of groups.
453  * @param int|bool $other Number of keys from the smallest groups to group into one single group (empty key) (true = half of
454  * average group size).
455  * @param int|bool $min Minimum group size (true = 10% of average group size).
456  * @param string $word Word mask (regex).
457  * @return array Group (key = common part) with keys from string list (value).
458  */
459  public static function groupByStart($array,$max = 25,$other = 0,$min = true,$word = '\\W+\\w*'){
460  $other = ($other === true) ? floor(count($array) / $max / 2) : min($other,count($array));
461  $min = max(2,($min === true) ? floor(count($array) / $max / 10) : $min);
462  $result = $others = [];
463  foreach($array as $key => $value){
464  if(!array_key_exists($value,$result)) $result[$value] = [];
465  $result[$value][] = $key;
466  }
467  if(count($result) > $max){
468  $groups = $result;
469  foreach($array as $key => $value) while(($value = preg_replace("/$word\$/",'',$value,1,$count)) && $count){
470  if(!array_key_exists($value,$groups)) $groups[$value] = [];
471  $groups[$value][] = $key;
472  }
473  foreach($groups as $value => $keys)
474  if((count($keys) < $min) && preg_replace("/$word\$/",'',$value,1,$count) && $count) unset($groups[$value]);
475  uksort($groups,function($a,$b) use ($groups){
476  return ((count($groups[$a]) <=> count($groups[$b])) ?: (strlen($b) <=> strlen($a))) ?: ($a <=> $b);
477  });
478  do{
479  $length = strlen($group_value = self::key($groups));
480  $count = count($group_keys = self::value($groups));
481  $groups = array_slice($groups,1,null,true);
482  foreach($result as $value => $keys) if((substr($value,0,$length) == $group_value) && preg_match("/^$word/",substr($value,$length))){
483  if(count($keys) == $count) continue 2; //same group
484  unset($result[$value]);
485  }
486  $result += [$group_value => $group_keys];
487  $others = [];
488  if($other && (count($result) < $max + $other)){
489  $others_count = $size = 0;
490  do{
491  $size++;
492  $extra_others = [];
493  foreach($result as $value => $keys) if(count($keys) == $size) $extra_others[$value] = $keys;
494  if(($others_count += array_sum(array_map('count',$extra_others))) <= $other) $others += $extra_others;
495  }
496  while($others_count < $other);
497  }
498  }
499  while((count($result) - count($others) > $max) && $groups);
500  if($others){
501  $result = array_diff_key($result,$others);
502  $others = [null => call_user_func_array('array_merge',$others)];
503  }
504  }
505  return $others + self::sort($result,null,true);
506  }
507 
508 }
static key($array, $index=0)
Get the n-th key from an array.
Definition: Record.php:187
static add(&$array, $key, $value=null)
Add a value to an array if the key does not already exist.
Definition: Record.php:126
static deviation($array, &$average=null)
Calculate the mean average deviation of an array.
Definition: Record.php:375
static group($array, $column)
Group records by a column.
Definition: Record.php:340
static sort($array, $options=null, $key=false)
Sort an array.
Definition: Record.php:399
static expand($array, $key_glue)
Brings a flattend array back to its multi-dimensional form.
Definition: Record.php:166
static groupByLetter($array, $length=1, $case_sensitive=false)
Group a list of strings by its first letter(s).
Definition: Record.php:439
static changeKey($array, $keys, $keep=true)
Change the keys of an array.
Definition: Record.php:296
static merge(... $arrays)
Merge arrays while preserving (duplicate) key sequence.
Definition: Record.php:216
static implode($array, $delimiter=null, $separator=null)
Enhanced implode.
Definition: Record.php:40
static column($array, $column)
Return the values from a single column in the input array.
Definition: Record.php:329
static resize($array, $length, $filler=null)
Set the length of an array.
Definition: Record.php:240
static shuffle($array)
Shuffle an array.
Definition: Record.php:354
static prefix($array, $prefix)
Add a prefix to all members of an array.
Definition: Record.php:273
static explode($array, $delimiter=null, $separator=null)
Enhanced explode.
Definition: Record.php:17
Record (array) helpers.
Definition: Record.php:8
static iget($array, $key, $default=null)
Get a value from an array in a case insensitive way.
Definition: Record.php:85
static value($array, $index=0, $default=null)
Get the n-th value from an array.
Definition: Record.php:178
static select($array, $keys)
Return specific keys from an array.
Definition: Record.php:387
static isearch($array, $value)
Searches the array for a given value and returns the first corresponding key if successful.
Definition: Record.php:261
static combine($keys, $values, $filler=null)
Creates an array by using one array for keys and another for its values.
Definition: Record.php:251
Definition: Color.php:3
static average($array)
Calculate the average of an array.
Definition: Record.php:366
static mergeKey($array, $key_name=null, $value_name=null)
Merge the key and value of an assoc.array into a record.
Definition: Record.php:311
static splice($array, $offset, $length=0, $replace=null)
Splice with keys.
Definition: Record.php:206
static prefixKey($array, $prefix)
Add a prefix to all keys of an array.
Definition: Record.php:284
static exists($array, $key)
Checks if a key exists in an array.
Definition: Record.php:53
static assoc($array)
Determine if an array is associative (that is, no ascending numerical key).
Definition: Record.php:195
static ranges($array)
Retrieve numerical ranges from an array.
Definition: Record.php:415
static flatten($array, $key_glue=null, $key_prefix=null)
Flattens a multi-dimensional array.
Definition: Record.php:153
static groupByStart($array, $max=25, $other=0, $min=true, $word='\\W+\\w *')
Group a list of strings by its most common start.
Definition: Record.php:459