$row) { if (!array_key_exists($columnName, $row)) { return $result; } if ((Qs_Array::FETCH_UNIQUE & $fetchMode) && in_array($row[$columnName], $result)) { continue; } if ((Qs_Array::FETCH_ASSOC & $fetchMode)) { $result[$key] = $row[$columnName]; } else { $result[] = $row[$columnName]; } } return $result; } public static function fetchColAll(array $list, $columnName) { $result = array(); foreach ($list as $row) { if (array_key_exists($columnName, $row)) { $result[] = $row[$columnName]; } } return $result; } public static function sum(array $list, $columnName = false) { if (false !== $columnName) { $list = Qs_Array::fetchCol($list, $columnName); } return array_sum($list); } public static function max(array $list, $columnName = false, $default = null) { if (false !== $columnName) { $list = Qs_Array::fetchCol($list, $columnName); } if (empty($list)) { return $default; } return max($list); } public static function fetchPairs(array $list, array $bind = array()) { $result = array(); if (empty($list)) { return $result; } $firstRow = current($list); if (empty($bind)) { $bind = array_keys($firstRow); } if (count($bind) < 2) { throw new Qs_Exception('List or bind argument must have 2 or more values for each row'); } $keyName = array_shift($bind); $valueName = array_shift($bind); foreach ($list as $row) { $result[$row[$keyName]] = $row[$valueName]; } return $result; } public static function group($list, $columns, $exclude = null) { $result = array(); $columns = (array) $columns; if (null === $exclude) { $exclude = $columns; } foreach ($list as $row) { $parts = array(); foreach ($columns as $column) { if (static::AUTOINCREMENT === $column) { $parts[] = count(static::get($result, $parts, [])); } else { $parts[] = $row[$column]; } } Qs_Array::set($result, $parts, Qs_Array::excludeArray($row, $exclude)); } return $result; } public static function isAssoc($array) { $count = count($array); for ($i = 0; $i < $count; $i++) { if (!array_key_exists($i, $array)) { return true; } } return false; } public static function mergeAssoc() { $arguments = func_get_args(); $argumentsCount = func_num_args(); if ($argumentsCount < 2) { return false; } $array = array(); for ($i = 0; $i < $argumentsCount; $i++) { foreach ($arguments[$i] as $k => $v) { $array[$k] = $v; } } return $array; } public static function mergeDiff($array1, $array2) { return array_merge($array1, array_diff_key($array2, $array1)); } public static function diffRecursive($array1, $array2) { foreach ($array1 as $key => $value) { if (is_array($value)) { if (@!is_array($array2[$key])) { $difference[$key] = $value; } else { $new_diff = Qs_Array::diffRecursive($value, $array2[$key]); if (!empty($new_diff)) { $difference[$key] = $new_diff; } } } elseif ($value != @$array2[$key]) { $difference[$key] = $value; } } return !isset($difference) ? array() : $difference; } /** * @static * @param $firstArray mixed * @param $secondArray mixed * @return array */ public static function mergeRecursive($firstArray, $secondArray) { if (is_array($firstArray) && is_array($secondArray)) { foreach ($secondArray as $key => $value) { if (isset($firstArray[$key])) { $firstArray[$key] = Qs_Array::mergeRecursive($firstArray[$key], $value); } else { $firstArray[$key] = $value; } } } else { $firstArray = $secondArray; } return $firstArray; } /** * Array sorting * * $data, multidim array * $keys, array(array(key => col1, sort => desc), array(key => col2, type => numeric)) * * @param array $data * @param array $keys * @return array */ public static function multisort($data, $keys) { // List As Columns $cols = array(); foreach ($data as $key => $row) { foreach ($keys as $k){ $cols[$k['key']][$key] = $row[$k['key']]; } } // List original keys $idKeys = array_keys($data); // Sort Expression $i = 0; $sort = ''; foreach ($keys as $k) { if ($i > 0) { $sort .= ', '; } $sort .= '$cols[\'' . $k['key'] . '\']'; if (isset($k['sort'])) { $sort .= ', SORT_' . strtoupper($k['sort']); } if (isset($k['type'])) { $sort .= ', SORT_' . strtoupper($k['type']); } $i++; } $sort .= ', $idKeys'; $sort = 'array_multisort(' . $sort . ');'; eval($sort); // Rebuild Full Array $result = array(); foreach($idKeys as $idKey) { $result[$idKey] = $data[$idKey]; } return $result; } /** * @static * @param array $array * @param string $field * @param mixed $default * @return mixed * @throws Qs_Exception */ public static function get($array, $field, $default = null) { $array = (array) $array; if (false !== $field && null !== $field) { if (is_array($field)) { $parts = $field; } else { $field = str_replace(']', '', '' . $field); $parts = explode('[', $field); } while (null !== ($name = array_shift($parts))) { if (!array_key_exists($name, $array)) { return $default; } $array = $array[$name]; } } return $array; } public static function set(&$array, $field, $value) { if (false !== $field) { if (is_array($field)) { $parts = $field; } else { $field = str_replace(']', '', $field); $parts = explode('[', $field); } if (null !== ($name = array_shift($parts))) { if (empty($parts)) { $array[$name] = $value; } elseif (!array_key_exists($name, $array) || !is_array($array[$name])) { $array[$name] = array(); } Qs_Array::set($array[$name], $parts, $value); } } else { $array = $value; } } public static function remove(&$array, $field) { if (false !== $field) { if (is_array($field)) { $parts = $field; } else { $field = str_replace(']', '', $field); $parts = explode('[', $field); } if (($name = array_shift($parts))) { if (empty($parts)) { unset($array[$name]); } elseif (array_key_exists($name, $array)) { Qs_Array::remove($array[$name], $parts); } } } else { unset($array); } } public static function excludeArray($array1, $array2) { foreach ($array2 as $keyName) { if (is_array($keyName)) { $array1 = Qs_Array::excludeArray($array1, $keyName); } elseif (array_key_exists($keyName, $array1)) { unset($array1[$keyName]); } } return $array1; } public static function excludeKey() { $args = func_get_args(); return call_user_func_array('Qs_Array::exclude', $args); } /** * @static * @deprecated function deprecated in Release 3.0. Use excludeKey * @return bool|mixed */ public static function exclude() { if (func_num_args() < 2) { return false; } $args = func_get_args(); $array = array_shift($args); $array = Qs_Array::excludeArray($array, $args); return $array; } public static function excludeValue() { if (func_num_args() < 2) { return false; } $args = func_get_args(); $array = array_shift($args); $array = Qs_Array::excludeValues($array, $args); return $array; } public static function excludeValues(array $array, array $values) { foreach ($values as $value) { if (false !== ($index = array_search($value, $array))) { unset($array[$index]); } } return $array; } public static function collapse(array $array, $belongsTo = '') { $result = array(); foreach ($array as $key => $value) { $itemBelongsTo = $belongsTo . (empty($belongsTo) ? $key : '[' . $key . ']'); if (is_array($value)) { $result = array_merge($result, Qs_Array::collapse($value, $itemBelongsTo)); } else { $result[$itemBelongsTo] = $value; } } return $result; } public static function expand(array $array) { $result = array(); foreach ($array as $key => $value) { Qs_Array::set($result, $key, $value); } return $result; } /** * Swap 2 elements in array preserving keys * * @param array $array * @param mixed $key1 * @param mixed $key2 * @return array */ public static function swap($array, $key1, $key2) { if (!is_array($array) || empty($array) || !array_key_exists($key1, $array) || !array_key_exists($key2, $array) ) { return $array; } $value1 = $array[$key1]; $value2 = $array[$key2]; $result = array(); foreach($array as $key => $value) { if ((string) $key == (string) $key1) { $key = $key2; $value = $value2; } else if ((string) $key == (string) $key2) { $key = $key1; $value = $value1; } $result[$key] = $value; } return $result; } /** * Move an element inside an array preserving keys * $relpos should be like -1, +2... * * @param array $array * @param int $key * @param int $relpos * @return array */ public static function move($array, $key, $relpos) { if (!is_array($array) || empty($array) || !array_key_exists($key, $array) || !$relpos) { return $array; } $from = Qs_Array::keyPos($key, $array); if ($from === false) { return $array; } $to = $from + $relpos + ($relpos > 0 ? 1 : 0); $length = count($array); if ($to >= $length) { $val = $array[$key]; unset($array[$key]); $array[$key] = $val; } else { if ($to < 0) { $to = 0; } $new = array(); $x = 0; foreach ($array as $i => $v) { if ($x++ == $to) { $new[$key] = $array[$key]; } if ($i !== $key) { $new[$i]=$v; } } $array = $new; } return $array; } /** * Get a key position in array * * @param mixed $key * @param array $array * @return integer */ public static function keyPos($key, $array) { $position = 0; foreach ($array as $i => $v) { if ($key === $i) { return $position; } $position++; } return false; } /** * Return key by position * * @param int $position * @param array $array * @return integer */ public static function keyByPos($position, $array) { $x = 0; foreach ($array as $i => $v) { if ($position == $x++) { return $i; } } return false; } public static function implodeLast($separator, $lastSeparator, $array) { $arraySize = count($array); $separators = array(); if ($arraySize > 2) { $separators = array_fill(0, $arraySize - 2, $separator); } $separators[] = $lastSeparator; return Qs_Array::implode($separators, $array); } public static function implode() { $countArguments = func_num_args(); $arguments = func_get_args(); if ($countArguments == 2 && is_array($arguments[0])) { $string = ''; $separators = array_values($arguments[0]); $elements = array_values($arguments[1]); $countSepatarots = count($separators); $countElements = count($elements); for ($i = 0; $i < $countElements; $i++) { $string .= (0 == $i ? '' : $separators[($i - 1) % $countSepatarots]) . $elements[$i]; } return $string; } return call_user_func_array('implode', $arguments); } /** * Convert associated array to indexed array with associated items * @static * @param array $array Associated array * @param string $keyName * @param string $valueName * @return array Indexed array */ public static function assocToIndex(array $array, $keyName, $valueName) { $result = array(); foreach ($array as $key => $value) { $result[] = array($keyName => $key, $valueName => $value); } return $result; } /** * Convert indexed array to associated * [['name' => 'foo', ...], ['name' => 'bar', ...], ...] * => ['foo' => ['name' => 'foo', ...], 'bar' => ['name' => 'bar', ...], ...] * @static * @param array $array Indexed array * @param string $colName * @return array */ public static function indexToAssoc(array $array, $colName = null) { $result = array(); if (empty($array) || !is_array($array)) { return $result; } if (null === $colName && ($first = reset($array)) && is_array($first)) { $colName = key($first); } if ($colName) { foreach ($array as $value) { if (is_array($value) && array_key_exists($colName, $value)) { $result[$value[$colName]] = $value; } } } return $result; } /** * Return array containing values from $source specified by $map ([$destination] => $source) * * Example: * * $values = array('map', 'class' => 'Qs_Array', 'framework' => 'qsf2', 'ver' => array(2, 0)); * $map = array( * 'function' => 0, * 'class', * 'framework' => array('source' => 'framework', 'callback' => 'strtoupper'), * 'version' => 'ver[0]', * ); * $result = Qs_Array::map($values, $map); * // Return: array('function' => 'map', 'class' => 'Qs_Array', 'framework' => 'QSF2', 'version' => 2) * * @static * @param array $values Source array * @param array $map Array of pairs ([$destination] => string|array $source). * @return array */ public static function map($values, $map) { $result = array(); foreach ($map as $destination => $source) { $sourceKey = null; $callback = null; if (is_array($source)) { $sourceKey = (isset($source['source'])) ? $source['source'] : $destination; $callback = (isset($source['callback']) && is_callable($source['callback'])) ? $source['callback'] : null; } else { $sourceKey = $source; $destination = is_int($destination) ? $sourceKey : $destination; } if (is_array($sourceKey) || (is_string($sourceKey) && false !== strpos($sourceKey, '['))) { $value = self::get($values, $sourceKey, null); } else { $value = array_key_exists($sourceKey, $values) ? $values[$sourceKey] : null; } $result[$destination] = (isset($value) && isset($callback)) ? call_user_func($callback, $value) : $value; } return $result; } /** * Extract value from tree * @static * @param array $tree * @param string $valueField * @return array */ public static function treeValues(array $tree, $valueField = 'value') { $result = array(); self::_treeValues($tree, $valueField, $result); return $result; } /** * @internal * @static * @param array $tree * @param string $valueField * @param array $result * @return void */ protected static function _treeValues(array $tree, $valueField, array &$result) { foreach ((array) $tree as $node) { if (array_key_exists($valueField, $node)) { $result[] = $node[$valueField]; } if (!empty($node['sub'])) { self::_treeValues($node['sub'], $valueField, $result); } } return; } /** * Build tree from the array according to $idField and $parentIdFiled * @param array $list Two level array with source values * @param array $fields Field what will be copied to each node using Qs_Array::map() * @param string $idField * @param string $parentIdField * @return array */ public static function buildTree(array $list, $fields = array('id', 'title'), $idField = 'id', $parentIdField = 'parentId') { $result = array(); self::_buildNodeSub($list, $result, 0, $fields, $idField, $parentIdField); return $result; } protected static function _buildNodeSub(array &$list, array &$parentSub, $parentId = 0, $fields, $idField, $parentIdField) { foreach ($list as $key => $row) { if ($parentId == $row[$parentIdField]) { $node = self::map($row, $fields); unset($list[$key]); $node['sub'] = array(); self::_buildNodeSub($list, $node['sub'], $row[$idField], $fields, $idField, $parentIdField); if (empty($node['sub'])) { unset($node['sub']); } $parentSub[$row[$idField]] = $node; } } return; } /** * @param array $tree * @param $parentValue * @param string $parentKey default 'id' * @return array|null */ public static function treeBranch(array $tree, $parentValue, $parentKey = 'id') { if (0 == $parentValue) { return $tree; } foreach ($tree as $node) { if ($node[$parentKey] == $parentValue) { return $node['sub']; } if (!empty($node['sub'])) { if (null !== ($subTree = self::treeBranch($node['sub'], $parentValue, $parentKey))) { return $subTree; } } } return null; } /** * @static * @param $array * @param $index int * @param $value mixed */ public static function insertAfter(&$array, $index, $value) { $array = array_merge(array_slice($array, 0, $index + 1), (array) $value, array_slice($array, $index + 1)); } /** * @static * @param array $array * @param $afterKey * @param $insertKey * @param $insertValue */ public static function insertAfterAssoc(array &$array, $afterKey, $insertKey, $insertValue) { $result = array(); foreach ($array as $key => $value) { $result[$key] = $value; if ($key == $afterKey) { $result[$insertKey] = $insertValue; } } $array = $result; } /** * Example: * * $array = array('map', 'class' => 'Qs_Array', 'ver' => array('qsf3', 'flat')); * $result = Qs_Array::flatten($array); * // Return: array (0 => 'map', 1 => 'Qs_Array', 2 => 'qsf3', 3 => 'flat); * * * @static * @param array $array * @return array */ public static function flatten(array $array) { $result = array(); array_walk_recursive($array, function ($value) use (&$result) { $result[] = $value; }); return $result; } /** * * $array = array('name' => 'Philip Fry', 'phone' => '(067) 111-1111', 'address' => array('city' => 'New York', 'state' => 'NY', 'zip' => 90001)); * * $result = Qs_Array::flatten($array); * // Return: array('name' => 'Philip Fry', 'phone' => '(067) 111-1111', 'address[city]' => 'New York', 'address[state]' => 'NY', 'address[zip]' => 90001) * * $result = Qs_Array::flatten($array, true); * // Return: array('name' => 'Philip Fry', 'phone' => '(067) 111-1111', 'addressCity' => 'New York', 'addressState' => 'NY', 'addressZip' => 90001) * * * @static * @param array $array * @param bool $friendlyKeys * @param null $belongsTo * @return array */ public static function flattenAssoc(array $array, $friendlyKeys = false, $belongsTo = null) { $result = array(); foreach ($array as $key => $value) { if (null !== $belongsTo) { if ($friendlyKeys) { $key = $belongsTo . ucfirst($key); } else { $key = $belongsTo . '[' . $key . ']'; } } if (is_array($value)) { $result += static::flattenAssoc($value, $friendlyKeys, $key); } else { $result[$key] = $value; } } return $result; } /** * @static * @param array $list Associative list of nodes array(id => array(), ...) * @param string $parentIdField [OPTIONAL] * @param callable|null $callback [OPTIONAL] * @return array Result tree */ public static function assocToTree(array $list, $parentIdField = 'parentId', $callback = null) { $root = array(); foreach ($list as $id => $node) { if (null !== $callback) { if (false === $callback($list[$id])) { continue; } } if ($node[$parentIdField]) { if (isset($list[$node[$parentIdField]])) { $list[$node[$parentIdField]]['sub'][$id] = &$list[$id]; } } else { $root[$id] = &$list[$id]; } } return $root; } /** * @static * @param array $tree * @param callable $callback * @return void */ public static function treeWalk(array &$tree, $callback, $level = 0) { foreach ($tree as $index => $node) { if (false === $callback($tree[$index], $level)) { unset($tree[$index]); continue; } if (isset($tree[$index]['sub'])) { self::treeWalk($tree[$index]['sub'], $callback, $level + 1); } } return; } /** * @static * @param array $tree * @param callable $callback * @return void */ public static function treeWalkReverse(array &$tree, $callback) { foreach ($tree as $index => $node) { if (isset($tree[$index]['sub'])) { self::treeWalk($tree[$index]['sub'], $callback); } if (false === $callback($tree[$index])) { unset($tree[$index]); continue; } } return; } public static function filter($list, array $filter) { return array_filter($list, function ($row) use ($filter) { $diff = array_diff_assoc($filter, $row); return empty($diff); }); } }