PHP sorting 3 dimensional array - php

I know this would be an easy one but I don't get it. All answered I found on the net was... too complex to me, maybe.
Here is my typical array:
array(
(int) 0 => array(
'Conversation' => array(
'id' => '1',
'created' => '2012-08-04 00:00:00'
),
'ConversationUser' => array(
(int) 0 => array(
'id' => '1'
),
(int) 1 => array(
'id' => '2'
)
)
),
(int) 1 => array(
'Conversation' => array(
'id' => '2',
'created' => '2012-08-01 00:00:00'
),
'ConversationUser' => array(
(int) 0 => array(
'id' => '1'
),
(int) 1 => array(
'id' => '2'
)
)
));
I want to sort my data with ['Conversation']['created'] date, asc or desc.
Any simple answer ? :P
P.S. I can't use MYSQL sort, I retrieve the data one by one and create that array.

Use usort() :
usort($your_array, function($a, $b){
$a = strtotime($a['Conversation']['created']);
$b = strtotime($b['Conversation']['created']);
if ($a == $b) {
return 0;
}
return ($a > $b) ? -1 : 1;
});

You can use array_multisort to do this:
// $data is your array from the example
// first obtain the rows for sorting
$sortkeys = array();
foreach ($data as $row) {
$sortkeys[] = $row['Conversation']['created'];
}
// sort $data according to $sortkeys
array_multisort($sortkeys, $data);
var_dump($data);

You should have a look to uksort() and usort() functions, which let you customize the way arrays are sorted.
Either the solution is simple or complex, remember what Einstein said once: "Things should be always done as simple as possible, but never simpler than they really are".
If you have some trouble with these functions, we can give you further clues ;-)

You can use usort() (or, to maintain index association, uasort(). Example: (assumes your array is $arr):
usort($arr, function($a, $b) {
return
preg_replace('/\D/', '', $b['Conversation']['created'])
>
preg_replace('/\D/', '', $a['Conversation']['created']);
});
That will sort descending. Change > to < for ascending.

Related

Sort PHP multidimensional array based on child array value, then main array key

I have a PHP array like the following:
$array = array(
'06930' => array(
'count' => 20
),
'06905' => array(
'count' => 25
),
'06910' => array(
'count' => 15
),
'06903' => array(
'count' => 15
),
'06920' => array(
'count' => 10
),
'06940' => array(
'count' => 5
),
'06915' => array(
'count' => 10
),
);
Contains zip codes and some data (count, ...) related to that zip. I need to sort it based on count (DESC), and then sort it again based on zip code (ASC), so that the result will be as follows:
$array = array(
'06905' => array(
'count' => 25
),
'06930' => array(
'count' => 20
),
'06903' => array(
'count' => 15
),
'06910' => array(
'count' => 15
),
'06915' => array(
'count' => 10
),
'06920' => array(
'count' => 10
),
'06940' => array(
'count' => 5
),
);
Zip with bigger count will be above others, but if two zips have equal count, smaller zip will be above.
I can sort it based on count using:
uasort($array, function ($a, $b) {
return $b['count'] <=> $a['count'];
});
But can't sort based on zip afterwards.
I reviewed many similar questions and answers but still couldn't figure out how to sort second time by the main array key (zip).
Thanks for any tips.
use array_multisort()
array_multisort(array_column($array,'count'), SORT_DESC, SORT_NUMERIC,
array_keys($array), SORT_NUMERIC, SORT_ASC,$array);
Output: -https://3v4l.org/QCrZf
You can change it to use uksort() which gives you the keys to sort with, you will need to pass the array in as well (using use) so that it can access the values as well.
This checks if the counts are the same, if they are it will compare the keys instead...
uksort($array, function ($a, $b) use ($array) {
if ( $array[$b]['count'] == $array[$a]['count']) {
return $a <=> $b;
}
return $array[$b]['count'] <=> $array[$a]['count'];
});
The short version of #Nigel Ren's answer:
uksort($array, function ($a, $b) use ($array) {
return $array[$b]['count'] <=> $array[$a]['count'] ?: $a <=> $b;
});

Move items of an array into the start of a multidimensional array

I have an array that contains some other arrays, I will make a sample of the original structure below in order to understand my issue.
$foo = array(
[0] => array('name' => foo, 'offered' => 1)
[1] => array('name' => foo)
[2] => array('name' => foo, 'offered' => 1)
[3] => array('name' => foo, 'offered' => 1)
);
What i want to do is, to sort my array in order to get first every array that contains the key 'offered'. In the example above i need do get this type of order. [0],[2],[3],[1].
You could use uasort() with a custom comparison function.
$foo = array(
array('name' => 'mark', 'offered' => 1),
array('name' => 'joe'),
array('name' => 'bill', 'offered' => 1),
array('name' => 'hugo', 'offered' => 1)
);
uasort($foo, 'customSort');
function customSort($a, $b) {
$a = isset($a['offered']);
$b = isset($b['offered']);
if (($a && $b) || (!$a && !$b)) return 0;
else if ($a && !$b) return -1;
else return 1;
}
print_r($foo);
Please check:
http://php.net/manual/it/function.usort.php
http://php.net/manual/it/function.uasort.php
http://php.net/manual/it/function.uksort.php
Explanation: (a bit simplified for newcomers) When you sort an array with these special sorting functions, you can tell PHP to use a custom function to let it decide whether a value is "less than another" (and return 1) or "greater than" another (and return -1) or "equal to another" (and return 0).
This functions has as parameters ($a, $b) the two array items to compare.
In this case we decide that the ones where "offered" exists are "less than" the others, so they will be sorted first.
I would iterate and check if the key exists, depending on that, rebuild the array.
$final = [];
foreach ($foo as $r) {
if (isset($r['offered']))
array_unshift($final, $r);
else
array_push($final, $r);
}
var_dump($final);
I find the spaceship operator (php7+) to provide a very clean syntax.
Evaluate the offered column from both $a and $b to check if the column is set. If not the isset() false will be treated as 0, otherwise true will be treated as 1.
By writing $b on the left of the operator and $a on the right, DESC sorting is performed -- this positions all 1 (true) evaluations before 0 (false) evaluations.
Code: (Demo)
$array = [
['name' => 'a', 'offered' => 1],
['name' => 'b'],
['name' => 'c', 'offered' => 1],
['name' => 'd', 'offered' => 1],
['name' => 'e']
];
usort($array, function($a, $b) {
return isset($b['offered']) <=> isset($a['offered']);
});
var_export($array);
Output:
array (
0 =>
array (
'name' => 'a',
'offered' => 1,
),
1 =>
array (
'name' => 'c',
'offered' => 1,
),
2 =>
array (
'name' => 'd',
'offered' => 1,
),
3 =>
array (
'name' => 'b',
),
4 =>
array (
'name' => 'e',
),
)

How to sort associative array using sub-field of contained associative arrays in PHP?

How can I sort an associative array by one of its values?
For example:
$arr = array(
'ted' => array( 'age' => 27 ),
'bob' => array( 'age' => 18 ),
'jay' => array( 'age' => 24 )
);
$arr = ???
foreach ($arr as $person)
echo $person['age'], ', ';
So that the output is:
18, 24, 27
This is an oversimplified example just to demonstrate my question.
I still require that $arr is an associative array.
The uasort() function allows you to specify a callback function, which will be responsible of doing the comparison between two elements -- so, should do just well, if you implement the proper callback function.
Here, you'd have to implement a callback function that will receive two arrays -- and compmare the age item :
function callback($a, $b) {
if ($a['age'] > $b['age']) {
return 1;
} else if ($a['age'] < $b['age']) {
return -1;
}
return 0;
}
Using that function in the following portion of code :
$arr = array(
'ted' => array( 'age' => 27 ),
'bob' => array( 'age' => 18 ),
'jay' => array( 'age' => 24 )
);
uasort($arr, 'callback');
var_dump($arr);
You would get you this resulting array :
array
'bob' =>
array
'age' => int 18
'jay' =>
array
'age' => int 24
'ted' =>
array
'age' => int 27
This is a classical example where PHP 5.3 anonymous functions come in handy:
uasort($arr, function($a, $b) {
return $a['age'] - $b['age'];
});
The $a['age'] - $b['age'] is a small trick. It works because the callback function is expected to return a value < 0 is $a is smaller than $b and a value > 0 if $a is bigger than $b.
Since you're sorting on a value inside a sub array, there's not a built-in function that will do 100% of the work. I would do a user-defined sort with:
http://www.php.net/manual/en/function.uasort.php
Here's an example comparison function that returns its comparison based on this value in the nested array
<?php
// Comparison function
function cmp($left, $right) {
$age1 = $left['age'];
$age2 = $right['age'];
if ($age1 == $age2) {
return 0;
}
return ($age1 < $age2) ? -1 : 1;
}
uasort($array, 'cmp');
http://www.php.net/manual/en/array.sorting.php
This particular case will involve using one of the sort methods that use a callback to sort
You're not just sorting an associative array, you're sorting an associative array of associative arrays ;)
A uasort call is what you're after
uasort($array, function ($a, $b) {
if ($a['age'] === $b['age']) {
return 0;
}
return $a['age'] > $a['age'] ? 1 : -1;
});

How do I sort a multi-dimensional array by value?

I have an array as following and I want to order that array by the value of the key "attack". First keys of the arrays (15, 13, 18) are ID of some certain item from database, so I don't want these keys to be changed when the array is sorted. Any help would be greatly appreciated.
This is the array:
$data = array(
'15' => array(
'attack' => '45', 'defence' => '15', 'total' => '10'
),
'13' => array(
'attack' => '25', 'defence' => '15', 'total' => '10'
),
'18' => array(
'attack' => '35', 'defence' => '15', 'total' => '10'
)
);
Use uasort():
This function sorts an array such that array indices maintain their correlation with the array elements they are associated with, using a user-defined comparison function.
This is used mainly when sorting associative arrays where the actual element order is significant.
Example:
function cmp($a, $b) {
if ($a['attack'] == $b['attack']) {
return 0;
}
return ($a['attack'] < $b['attack']) ? -1 : 1;
}
uasort($data, 'cmp');
If the values are always strings, you can also use strcmp() in the cmp() function:
function cmp($a, $b) {
return strcmp($a['attack'], $b['attack']);
}
Update:
To sort in descending order you just have to change the return values:
return ($a['attack'] < $b['attack']) ? 1 : -1;
// ^----^
or to pick up #salathe's proposal:
return $b['attack'] - $a['attack'];
Simply use array_multisort
foreach ($data as $key => $row) {
$attack[$key] = $row['attack'];
}
// Sort the data with attack descending
array_multisort($attack, SORT_DESC, $data);
Hope this helps.
$result = [];
foreach ($data as $key => $value) {
$result[$key] = $value;
asort($result[$key]);
}
print_r($result);
Hope this helps !!!

How to sort an array based on a specific field in the array?

How can I sort an array based on two specific values within the array? For instance:
$arr = array(
array('a' => array('field1' => 'Abc', 'field2' => 'Def'), 'b' => 0)
array('a' => array('field1' => 'Ghi', 'field2' => 'Jkl'), 'b' => 0)
);
I want to sort this array based on the $arr[$i]['a']['field1'] variable. How can I do that?
Give this a try:
function cmp($a, $b) {
if ($a['a']['field1'] == $b['a']['field1'] )
return 0;
return ( $a['a']['field1'] < $b['a']['field1'] ) ? -1 : 1;
}
uasort($arr, 'cmp');
This is just a slight alteration of the example provided on the PHP documentation page:
http://www.php.net/manual/en/function.uasort.php
Create your own comparison function and use uasort
http://us.php.net/manual/en/function.uasort.php
in this particular case (sort on very first item of the very first subarray), simple sort() will be enough.

Categories