What I Need
i Need to create nesting array from existing array.
if in array both values type are same .
group according their type.
like array[1] type is same array[2] type so i need to group them in single nested array.
here is the array structure
$data=$event['data']['pricing_detail'];
[1] => Array
(
[type] => General Public Tickets Adult
[amount] => 50
[comment] => (Working Days)
)
[2] => Array
(
[type] => General Public Tickets Adult
[amount] => 80
[comment] => (Saturday/ Sunday/ Holiday)
)
i need output like
[1] => Array
(
[type] => General Public Tickets Adult
[metadata]=>array
(
[0] =>array
(
[amount] => 50
[comment] => (Working Days)
)
[1]=>array
(
[amount] => 80
[comment] => (Saturday/ Sunday/ Holiday)
)
)
)
code snippet
$data=$event['data']['pricing_detail'];
$metadata = array();
foreach($data as $key => $value)
{
if($value[1]['type'] == $value[2]['type'])
{
$metadata[$key]['amount'] = $value['amount'];
print_r($metadata);
}
else
{
echo "not matched";
}
}
Problem im facing im not able to make logic so to get desired result.
Loop your array, storing the types and the array they belong to.
Then loop the types and add te values.
//store types and the arrays the belong to
foreach($data as $k=>$v){
$type[$v['type']][]=$k;
}
//loop types, creating result array
foreach($type as $k=>$v){
$tmp=array(
'type'=>$k,
'metadata'=>array()
);
//loop all the arrays of this type
foreach($v as $w){
//store in TMP
$t=array(
'amount' => $vals[$w]['amount'],
'comment' => $vals[$w]['comment']
);
//sort TMP on EMPTY value
usort($t,function ($a, $b) {
if($a == '' && $b != '') return 1;
if($b == '' && $a != '') return -1;
if($b == 0){return 1;}
return 0;
});
//store
$tmp['metadata'][]=$t;
}
$result[]=$tmp;
}
echo '<pre>'.print_r($result,true).'<pre>';
Example:
$data=array(
1 => Array(
'type' => 'General Public Tickets Adult',
'amount' => 50,
'comment' => '(Working Days)'),
2 => Array (
'type' => 'General Public Tickets Adult',
'amount' => 80,
'comment' => '(Saturday/ Sunday/ Holiday)'),
3 => Array (
'type' => 'Special Tickets Children',
'amount' => 300,
'comment' => '(Saturday/ Sunday/ Holiday)'),
4 => Array (
'type' => 'Special Tickets Children',
'amount' => 10000,
'comment' => '(Monday afternoon)')
);
result:
Array
(
[0] => Array(
[type] => General Public Tickets Adult
[metadata] => Array(
[0] => Array(
[amount] => 50
[comment] => (Working Days)
)
[1] => Array(
[amount] => 80
[comment] => (Saturday/ Sunday/ Holiday)
)
)
)
[1] => Array(
[type] => Special Tickets Children
[metadata] => Array(
[0] => Array(
[amount] => 300
[comment] => (Saturday/ Sunday/ Holiday)
)
[1] => Array(
[amount] => 10000
[comment] => (Monday afternoon)
)
)
)
)
[edit] updated with usort for sorting empty 'comments';
[edit] added line to usort to prevent unwanted sorting when tickets = 0;
And a fiddle
You have too create a new tickets array, with first dimention being the contents of type and second dimension being it's original id.
Something like this:
$grouped = array();
foreach($data as $key => $value) {
$grouped[$value['type']][$key] = $value;
unset($grouped[$value['type']][$key]["type"]);
}
print_r($grouped);
Adjust according to your array structure, I cant see the your actual structure of $data in your samples.
If you want to sort a multilevel array, you can use a variation of this function:
/**
* sort an multidimensional array by any of it's fields and return sorted array
* ex.: $sorted = multisort($data, 'volume', SORT_DESC, 'edition', SORT_ASC);
* IMPORTANT: This function uses mutlisort and will reindex numeric keys !
* #param array $data array to sort
* #param string $field name of field to sort by
* #param int $direction SORT_DESC or SORT_ASC constant
* #return array
*/
function multisort(){
$args = func_get_args();
$data = array_shift($args);
foreach ($args as $n => $field) {
if (is_string($field)) {
$tmp = array();
foreach ($data as $key => $row)
$tmp[$key] = $row[$field];
$args[$n] = $tmp;
}
}
$args[] = &$data;
call_user_func_array('array_multisort', $args);
return array_pop($args);
}
Used like this:
foreach($grouped as $type => &$list)
$list = multisort($list, 'comment', SORT_DESC);
Related
I have a multidimensional array and am trying to group them according to the value in a specific column.
I'm trying to group them by level, but I won't actually know the level beforehand. So, it's not like I can put it in a for loop and say while $i < 7, because I won't know that 7 is the maximum value for the level key, and frankly, I'm not sure that's how I would need to do it even if I did.
[
['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]
Desired result:
Array (
[1] => Array (
[0] => Array (
[cust] => XT8900
[type] => standard
)
[1] => Array (
[cust] => XT8944
[type] => standard
)
)
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
)
Best way, if you have control over building the initial array, is just set things up like that at the start as you add entries.
If not then build a temporary array to sort:
foreach ($input_arr as $key => &$entry) {
$level_arr[$entry['level']][$key] = $entry;
}
Leaves you with the form you wanted and everything referenced together.
Build the array like that in the first place though if at all possible.
You need to group them by level first
Use foreach to loop into array check if the level is the same with the previous item then group it with that array
$templevel=0;
$newkey=0;
$grouparr[$templevel]="";
foreach ($items as $key => $val) {
if ($templevel==$val['level']){
$grouparr[$templevel][$newkey]=$val;
} else {
$grouparr[$val['level']][$newkey]=$val;
}
$newkey++;
}
print($grouparr);
The output of print($grouparr); will display like the format you hoped for
You can also try to
print($grouparr[7]);
Will display
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
Or
print($grouparr[3]);
Will display
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
Here is the solution I landed on for an identical problem, wrapped as a function:
function arraySort($input,$sortkey){
foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
return $output;
}
To sort $myarray by the key named "level" just do this:
$myArray = arraySort($myArray,'level');
Or if you didn't want it as a function, just for a one time use, this would create $myNewArray from $myArray grouped by the key 'level'
foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;
function group_assoc($array, $key) {
$return = array();
foreach($array as $v) {
$return[$v[$key]][] = $v;
}
return $return;
}
//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');
$result = array();
foreach ($yourArrayList as $data) {
$id = $data['level'];
if (isset($result[$id])) {
$result[$id][] = $data;
} else {
$result[$id] = array($data);
}
}
Best ans.
$levels = array_unique(array_column($records, 'level'));
$data = array();
foreach($records as $key => $value){
$data[$levels[array_search($value['level'],$levels )]][] = $value ;
}
print_r($data);
To generate the question's exact desured output from the sample input, pull/pop the last value from each row, use that value as the first level grouping key. Then use the original first level index as the second level key. Then push the two remaining elements into the group's subset.
Code: (Demo)
$result = [];
foreach ($array as $key => $row) {
$result[array_pop($row)][$key] = $row;
}
var_export($result);
For functional style syntax, use array_reduce(). (Demo)
var_export(
array_reduce(
array_keys($array),
function($result, $key) use ($array) {
$result[array_pop($array[$key])][$key] = $array[$key];
return $result;
}
)
);
function _group_by($array,$key,$keyName)
{
$return = array();
foreach($array as $val) {
$return[$keyName.$val[$key]][] = $val;
}
return $return;
} //end of function
I have an array with same customerid. I want to merge all same customerid arrays in to one with few amends to the array.
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[customerid] => 1
[customer_fullname] => John
[profession_id] => 8
[profession_name] => Producer
)
[2] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[profession_id] => 7
[profession_name] => Camera
)
)
So now I want a new array to be created like this:
Array(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => array(
[0]=>[profession_id] => 8, [profession_name] => Producer,
[1]=>[profession_id] => 7, [profession_name] => Camera
)
)
Spent some time on it but wasn't able to get it right
There are better approaches if you're merging lots of records, but if you want a way to just merge two records as stated, I'd just do this:
$array1 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 8,
'profession_name' => 'Producer'
);
$array2 = array(
'customerid' => 13
'customer_fullname' => 'John',
'profession_id' => 7,
'profession_name' => 'Director'
);
function merge_customers($customerA, $customerB)
{
$newCustomer = array();
if ($customerA['customerid'] == $customerB['customerid'])
{
$newCustomer['customerid'] = $customerA['customerid'];
$newCustomer['customer_fullname'] = $customerA['customer_fullname'];
$newCustomer['new_array'] = array(
array(
'profession_id' => $customerA['profession_id'],
'profession_name' => $customerA['profession_name']
),
array(
'profession_id' => $customerB['profession_id'],
'profession_name' => $customerB['profession_name']
)
);
return $newCustomer;
}
/* We can't merge these if they're different customers. */
return NULL;
}
The extended solution which is also well-suited for finding and "merging" multiple groups of entries which has same customerid. Used functions: array_filter, array_count_values, array_keys, array_walk, array_chunk and array_values:
// supposing $arr is your initial array
// finds which 'customerid' has multiple entries
$dupIds = array_filter(array_count_values(array_column($arr, "customerid")), function($v) {
return $v > 1;
});
$dupIds = array_keys($dupIds);
$result = [];
array_walk($arr, function($v) use(&$result, $dupIds) {
if (in_array($v['customerid'], $dupIds)) {
$parts = array_chunk($v, 2, true);
if (!isset($result[$v['customerid']])) {
$result[$v['customerid']] = $parts[0] + ['new_array' => [$parts[1]]];
} else {
$result[$v['customerid']]['new_array'][] = $parts[1];
}
}
});
print_r(array_values($result));
The output:
Array
(
[0] => Array
(
[customerid] => 13
[customer_fullname] => Chris
[new_array] => Array
(
[0] => Array
(
[profession_id] => 8
[profession_name] => Producer
)
[1] => Array
(
[profession_id] => 7
[profession_name] => Camera
)
)
)
)
Quick hack, maybe there is a nicer solution.
Note: The second "for each" loop is only needed if there is the possibility that the arrays don't have the same fields.
function merge($array1, $array2){
$result = array();
foreach($array1 as $key => $value){
if(isset($array2[$key]) && $array2[$key]!=$array1[$key]){
$result[$key][]=$value;
$result[$key][]=$array2[$key];
}else{
$result[$key]=$value;
}
}
foreach($array2 as $key => $value){
if(!isset($result[$key])){
$result[$key] = $value;
}
}
return $result;
}
print_r(merge($array1, $array2));
I have a large multidimensional array something like the below:
Array(
[1] => Array ( [type] => blah1 [category] => cat1 [exp_range] => this_week )
[2] => Array ( [type] => blah1 [category] => cat2 [exp_range] => next week )
[3] => Array ( [type] => blah1 [category] => cat1 [exp_range] => next week )
[4] => Array ( [type] => blah2 [category] => cat2 [exp_range] => this_week )
)
I want to be able to filter this array with multiple filters.
eg. filtering where category = cat1 and type = blah1 would return array 1 and 3.
I have the below function that would return keys 1,2,3 which is incorrect as array 2 doesnt have both cat1 and blah1
Can anyone see what I need to do to get this working?
Also would it be possible to incorporate sortin in this function, if so how?
function array_searcher($needles, $array) {
foreach ($needles as $needle) {
foreach ($array as $key => $value) {
foreach ($value as $v) {
if ($v == $needle) {
$keys[] = $key;
}
}
}
}
return $keys;
}
I decided to rewrite my answer to accommodate both filtering and sorting. I took a heavily object oriented approach to solving this problem, which I will detail below.
You can see all of this code in action at this ideone.com live demonstration.
The first thing I did was define two interfaces.
interface Filter {
public function filter($item);
}
interface Comparator {
public function compare($a, $b);
}
As their names suggest, Filter is used for filtering, and Comparator is used for comparing.
Next, I defined three concrete classes that implements these interfaces, and accomplish what I wanted.
First is KeyComparator. This class simply compares the key of one element to the key of another element.
class KeyComparator implements Comparator {
protected $direction;
protected $transform;
protected $key;
public function __construct($key, $direction = SortDirection::Ascending, $transform = null) {
$this->key = $key;
$this->direction = $direction;
$this->transform = $transform;
}
public function compare($a, $b) {
$a = $a[$this->key];
$b = $b[$this->key];
if ($this->transform) {
$a = $this->transform($a);
$b = $this->transform($b);
}
return $a === $b ? 0 : (($a > $b ? 1 : -1) * $this->direction);
}
}
You can specify a sort direction, as well as a transformation to be done to each element before they are compared. I defined a helped class to encapsulate my SortDirection values.
class SortDirection {
const Ascending = 1;
const Descending = -1;
}
Next, I defined MultipleKeyComparator which takes multiple KeyComparator instances, and uses them to compare two arrays against each other. The order in which they are added to the MultipleKeyComparator is the order of precedence.
class MultipleKeyComparator implements Comparator {
protected $keys;
public function __construct($keys) {
$this->keys = $keys;
}
public function compare($a, $b) {
$result = 0;
foreach ($this->keys as $comparator) {
if ($comparator instanceof KeyComparator) {
$result = $comparator->compare($a, $b);
if ($result !== 0) return $result;
}
}
return $result;
}
}
Finally, I created MultipleKeyValueFilter which is meant to filter an array based on an array of key/value pairs:
class MultipleKeyValueFilter implements Filter {
protected $kvPairs;
public function __construct($kvPairs) {
$this->kvPairs = $kvPairs;
}
public function filter($item) {
$result = true;
foreach ($this->kvPairs as $key => $value) {
if ($item[$key] !== $value)
$result &= false;
}
return $result;
}
}
Now, given the input array (Notice I rearranged them a bit to make the sorting obvious):
$array = array (
'1' => array ('type' => 'blah2', 'category' => 'cat2', 'exp_range' => 'this_week' ),
'2' => array ('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'this_week' ),
'3' => array ('type' => 'blah1', 'category' => 'cat2', 'exp_range' => 'next_week' ),
'4' => array ('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'next_week' )
);
Sorting can be achieved by doing the following:
$comparator = new MultipleKeyComparator(array(
new KeyComparator('type'),
new KeyComparator('exp_range')
));
usort($array, array($comparator, 'compare'));
echo "Sorted by multiple fields\n";
print_r($array);
Filtering can be achieved by doing the following:
$filter = new MultipleKeyValueFilter(array(
'type' => 'blah1'
));
echo "Filtered by multiple fields\n";
print_r(array_filter($array, array($filter, 'filter')));
At this point I've given you a great deal of code. I'd suggest that your next step is to combine these two pieces into a single class. This single class would then apply both filtering and sorting together.
Do it:
$arr = array(
1 => array ( "type" => "blah1", "category" => "cat1", "exp_range" => "this_week" ),
2 => array ( "type" => "blah1", "category" => "cat2", "exp_range" => "next week" ),
3 => array ( "type" => "blah1", "category" => "cat1", "exp_range" => "this_week" ),
4 => array ( "type" => "blah2", "category" => "cat2","exp_range" => "next week" ),
);
function filter(array $arr,array $params){
$out = array();
foreach($arr as $key=>$item){
$diff = array_diff_assoc($item,$params);
if (count($diff)==1) // if count diff == 1 - Ok
$out[$key] = $item;
}
return $out;
}
$out = filter($arr,array("type" => "blah1", "category" => "cat1"));
echo '<pre>';
print_r($out);
echo '</pre>';
// output
Array
(
[1] => Array
(
[type] => blah1
[category] => cat1
[exp_range] => this_week
)
[3] => Array
(
[type] => blah1
[category] => cat1
[exp_range] => this_week
)
)
The issue is the fact that your function will return the key of every array that contains "cat1" or "blah1". You can fix it with array_unique():
function array_searcher($needles, $array) {
foreach ($needles as $needle) {
foreach ($array as $key => $value) {
foreach ($value as $v) {
if ($v == $needle) {
$keys[] = $key;
}
}
}
}
return $keys;
}
$bigarray = array(
array('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'this_week'),
array('type' => 'blah1', 'category' => 'cat2', 'exp_range' => 'next week'),
array('type' => 'blah1', 'category' => 'cat1', 'exp_range' => 'next week'),
array('type' => 'blah2', 'category' => 'cat2', 'exp_range' => 'this_week')
);
$result = array_searcher(array('cat1','blah1'), $bigarray);
$unique_result = array_unique($result);
print_r($unique_result);
so lets assign your base array to a variable:
$array = Array(
[1] => Array ( [type] => blah1 [category] => cat1 [exp_range] => this_week )
[2] => Array ( [type] => blah1 [category] => cat2 [exp_range] => next week )
[3] => Array ( [type] => blah1 [category] => cat1 [exp_range] => next week )
[4] => Array ( [type] => blah2 [category] => cat2 [exp_range] => this_week )
)
and lets's have an array containing our filter:
$filter = array(
'type' => 'blah1'
'category' => 'cat1'
)
then we start our filtering script
foreach ($array as $key => $row){
$i = 0;
foreach ($filter as $filterKey => $filterValue){
if ($row[$filterKey] != $filterValue){
$i++;
}}
if ($i == 0){
$filteredArray[] = $row;
}}
if $i still equals 0 after the row is tested against our filter, we add the row to our filtered array
I vaguely remember implementing this type of functionality many years ago:
http://forums.devnetwork.net/viewtopic.php?t=47855
Look to the sortRows() and _quickSort() methods
HTH
I need a PHP function that can assert that two arrays are the same while ignoring the values of a specified set of keys (only the value, the keys must match).
In practice, the arrays must have the same structure, but some values can be ignored.
For example, considering the following two arrays:
Array
(
[0] => Array
(
[id] => 0
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
)
Array
(
[0] => Array
(
[id] => 1
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
)
they are the same if we ignore the value of the key id.
I also want to consider the possibility of nested arrays:
Array
(
[0] => Array
(
[id] => 0
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
[1] => Array
(
[id] => 0
[title] => Book2 Title
[creationDate] => 2013-01-13 18:01:07
[pageCount] => 0
)
)
Array
(
[0] => Array
(
[id] => 2
[title] => Book1 Title
[creationDate] => 2013-01-13 17:01:07
[pageCount] => 0
)
[1] => Array
(
[id] => 3
[title] => Book2 Title
[creationDate] => 2013-01-13 18:01:07
[pageCount] => 0
)
)
Since I need it for testing, I have come up with the following class that extends PHPUnit_Framework_TestCase and uses its assert functions:
class MyTestCase extends PHPUnit_Framework_TestCase
{
public static function assertArraysSame($expected, $actual, array $ignoreKeys = array())
{
self::doAssertArraysSame($expected, $actual, $ignoreKeys, 1);
}
private static function doAssertArraysSame($expected, $actual, array $ignoreKeys = array(), $depth, $maxDepth = 256)
{
self::assertNotEquals($depth, $maxDepth);
$depth++;
foreach ($expected as $key => $exp) {
// check they both have this key
self::assertArrayHasKey($key, $actual);
// check nested arrays
if (is_array($exp))
self::doAssertArraysSame($exp, $actual[$key], $ignoreKeys, $depth);
// check they have the same value unless the key is in the to-ignore list
else if (array_search($key, $ignoreKeys) === false)
self::assertSame($exp, $actual[$key]);
// remove the current elements
unset($expected[$key]);
unset($actual[$key]);
}
// check that the two arrays are both empty now, which means they had the same lenght
self::assertEmpty($expected);
self::assertEmpty($actual);
}
}
doAssertArraysSame iterates through one of the arrays and asserts recursively that the two arrays have the same keys. It also checks that they have the same values unless the current key is in the list of the keys to ignore.
To make sure the two arrays have exactly the same number of elements, each element is removed during the iteration and, at the end of the loop, the function checks that both arrays are empty.
Usage:
class MyTest extends MyTestCase
{
public function test_Books()
{
$a1 = array('id' => 1, 'title' => 'the title');
$a2 = array('id' => 2, 'title' => 'the title');
self::assertArraysSame($a1, $a2, array('id'));
}
}
My question is: is there a better or simpler way to accomplish this task, maybe using some already available PHP/PHPUnit functions?
EDIT: please bear in mind I don't necessarily want a solution for PHPUnit, if there was a plain PHP function that can do this, I can use it in my tests.
I'm not sure if this is a better solution than what you're already using, but I've used a similar class before when I had this exact need. It is able to give you a simple true or false response and isn't coupled to a testing framework, which may or may not be a good thing for you.
class RecursiveArrayCompare
{
/**
* #var array
*/
protected $ignoredKeys;
/**
*
*/
function __construct()
{
$this->ignoredKeys = array();
}
/**
* #param array $ignoredKeys
* #return RecursiveArrayCompare
*/
public function setIgnoredKeys(array $ignoredKeys)
{
$this->ignoredKeys = $ignoredKeys;
return $this;
}
/**
* #param array $a
* #param array $b
* #return bool
*/
public function compare(array $a, array $b)
{
foreach ($a as $key => $value) {
if (in_array($key, $this->ignoredKeys)) {
continue;
}
if (!array_key_exists($key, $b)) {
return false;
}
if (is_array($value) && !empty($value)) {
if (!is_array($b[$key])) {
return false;
}
if (!$this->compare($value, $b[$key])) {
return false;
}
} else {
if ($value !== $b[$key]) {
return false;
}
}
unset($b[$key]);
}
$diff = array_diff(array_keys($b), $this->ignoredKeys);
return empty($diff);
}
}
And some examples based on your provided array:
$arr1 = array(
'id' => 0,
'title' => 'Book1 title',
'creationDate' => '2013-01-13 17:01:07',
'pageCount' => 0
);
// only difference is value of ignored key
$arr2 = array(
'id' => 1,
'title' => 'Book1 title',
'creationDate' => '2013-01-13 17:01:07',
'pageCount' => 0
);
// has extra key
$arr3 = array(
'id' => 1,
'title' => 'Book1 title',
'creationDate' => '2013-01-13 17:01:07',
'pageCount' => 0,
'extra_key' => 1
);
// has extra key, which is ignored
$arr4 = array(
'id' => 1,
'title' => 'Book1 title',
'creationDate' => '2013-01-13 17:01:07',
'pageCount' => 0,
'ignored_key' => 1
);
// has different value
$arr5 = array(
'id' => 2,
'title' => 'Book2 title',
'creationDate' => '2013-01-13 17:01:07',
'pageCount' => 0
);
$comparer = new RecursiveArrayCompare();
$comparer->setIgnoredKeys(array('id', 'ignored_key'));
var_dump($comparer->compare($arr1, $arr2)); // true
var_dump($comparer->compare($arr1, $arr3)); // false
var_dump($comparer->compare($arr1, $arr4)); // true
var_dump($comparer->compare($arr1, $arr5)); // false
EDIT
The benefit to using a separate class such as this is that it's straight forward to unit test this class as well to ensure it behaves as expected. You don't want to rely on tools for your tests if you can't guarantee that they're working properly.
You could foreach the array elements
foreach ($array1 as $index => $subArray)
{
$this->assertEquals($array1[$index]['title'], $array2[$index]['title');
$this->assertEquals($array1[$index]['creationDate'], $array2[$index]['creationDate');
$this->assertEquals($array1[$index]['pageCount'], $array2[$index]['pageCount');
}
I have a multidimensional array and am trying to group them according to the value in a specific column.
I'm trying to group them by level, but I won't actually know the level beforehand. So, it's not like I can put it in a for loop and say while $i < 7, because I won't know that 7 is the maximum value for the level key, and frankly, I'm not sure that's how I would need to do it even if I did.
[
['cust' => 'XT8900', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8944', 'type' => 'standard', 'level' => 1],
['cust' => 'XT8922', 'type' => 'premier', 'level' => 3],
['cust' => 'XT8816', 'type' => 'permier', 'level' => 3],
['cust' => 'XT7434', 'type' => 'standard', 'level' => 7],
]
Desired result:
Array (
[1] => Array (
[0] => Array (
[cust] => XT8900
[type] => standard
)
[1] => Array (
[cust] => XT8944
[type] => standard
)
)
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
)
Best way, if you have control over building the initial array, is just set things up like that at the start as you add entries.
If not then build a temporary array to sort:
foreach ($input_arr as $key => &$entry) {
$level_arr[$entry['level']][$key] = $entry;
}
Leaves you with the form you wanted and everything referenced together.
Build the array like that in the first place though if at all possible.
You need to group them by level first
Use foreach to loop into array check if the level is the same with the previous item then group it with that array
$templevel=0;
$newkey=0;
$grouparr[$templevel]="";
foreach ($items as $key => $val) {
if ($templevel==$val['level']){
$grouparr[$templevel][$newkey]=$val;
} else {
$grouparr[$val['level']][$newkey]=$val;
}
$newkey++;
}
print($grouparr);
The output of print($grouparr); will display like the format you hoped for
You can also try to
print($grouparr[7]);
Will display
[7] => Array (
[4] => Array (
[cust] => XT7434
[type] => standard
)
)
Or
print($grouparr[3]);
Will display
[3] => Array (
[2] => Array (
[cust] => XT8922
[type] => premier
)
[3] => Array (
[cust] => XT8816
[type] => permier
)
)
Here is the solution I landed on for an identical problem, wrapped as a function:
function arraySort($input,$sortkey){
foreach ($input as $key=>$val) $output[$val[$sortkey]][]=$val;
return $output;
}
To sort $myarray by the key named "level" just do this:
$myArray = arraySort($myArray,'level');
Or if you didn't want it as a function, just for a one time use, this would create $myNewArray from $myArray grouped by the key 'level'
foreach ($myArray as $key=>$val) $myNewArray[$val['level']][]=$val;
function group_assoc($array, $key) {
$return = array();
foreach($array as $v) {
$return[$v[$key]][] = $v;
}
return $return;
}
//Group the requests by their account_id
$account_requests = group_assoc($requests, 'account_id');
$result = array();
foreach ($yourArrayList as $data) {
$id = $data['level'];
if (isset($result[$id])) {
$result[$id][] = $data;
} else {
$result[$id] = array($data);
}
}
Best ans.
$levels = array_unique(array_column($records, 'level'));
$data = array();
foreach($records as $key => $value){
$data[$levels[array_search($value['level'],$levels )]][] = $value ;
}
print_r($data);
To generate the question's exact desured output from the sample input, pull/pop the last value from each row, use that value as the first level grouping key. Then use the original first level index as the second level key. Then push the two remaining elements into the group's subset.
Code: (Demo)
$result = [];
foreach ($array as $key => $row) {
$result[array_pop($row)][$key] = $row;
}
var_export($result);
For functional style syntax, use array_reduce(). (Demo)
var_export(
array_reduce(
array_keys($array),
function($result, $key) use ($array) {
$result[array_pop($array[$key])][$key] = $array[$key];
return $result;
}
)
);
function _group_by($array,$key,$keyName)
{
$return = array();
foreach($array as $val) {
$return[$keyName.$val[$key]][] = $val;
}
return $return;
} //end of function