Sorting of three dimensional array - php

I am trying to fill an array with values:
foreach($pallets as $pallet){
$i++;
$orders[$i]['id'] = $pallet->id;
$orders[$i]['reference'] = $pallet->reference;
$orders[$i]['created_at'] = $pallet->created_at;
$orders[$i]['status'] = $pallet->getStatus();
}
How can i order the values ($i) inside the array by their created_at attribute?
Many thanks

Extract the created_at column and sort that while sorting the original array the same:
array_multisort(array_column($orders, 'created_at'), SORT_ASC, $orders);
This assumes that created_at is in a format that sorts correctly such as 2016-02-18 12:00. If not, but if it is still a valid date/time try:
array_multisort(array_map('strtotime', array_column($orders, 'created_at')),
SORT_ASC,
$orders);

Use usort (http://php.net/manual/en/function.usort.php):
function cmp($a, $b)
{
if ($a["created_at"] == $b["created_at"]) {
return 0;
}
return ($a["created_at"] < $b["created_at"]) ? -1 : 1;
}
usort($orders, "cmp");
foreach ($orders as $key => $value) {
echo "$key: $value\n";
}

Related

Need help to order strings by their internal value

I am using a text file as little database, and each line has this format:
3692|Giovanni|giojo982|0005405
9797|Stefano|stefy734|45367
2566|Marco|markkkk998|355647689
4721|Roberto|robn88|809678741
I need to order them alphabetically maintaining their indexes, if it's possible.
At the moment, I'm using this code, but in this situation logically it doesn't work any more.
Reading this post How can I sort arrays and data in PHP? I have not found nothing similar to my scenario.
So, I'm wondering... is there a solution?
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
if(isset($_GET['A-Z'])) {
asort($dblines);
}
if(isset($_GET['Z-A'])) {
arsort($dblines);
}
foreach($dblines as $key => $profile) {
list($uni_id, $name_surname, $textnum_id, $num_id) = explode("|", $profile);
echo $name_surname;
}
A-Z
Z-A
How can I solve it?
I assume by alphabetically that you're trying to sort alphabetically by the name in the second column. The problem is, asort() and arsort() perform too simple a comparison to deal with the type of data you're giving them. They're just going to see the rows as strings, and sort by the number in the first column. One way to address this is by splitting the rows before sorting.
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
// split each line into an array
$dblines = array_map(function($line){
return explode('|', $line);
}, $dblines);
Then you can sort by the second column more easily. Using uasort(), you'll maintain the index association.
if (isset($_GET['A-Z'])) {
uasort($dblines, function(array $a, array $b) {
return strcmp($a[1], $b[1]);
});
}
if (isset($_GET['Z-A'])) {
uasort($dblines, function(array $a, array $b) {
return strcmp($b[1], $a[1]);
});
}
Obviously if you make that change, you'll no longer need to explode when you iterate the sorted array, as it was already done in the first step.
foreach ($dblines as $key => $profile) {
list($uni_id, $name_surname, $textnum_id, $num_id) = $profile;
echo $name_surname;
}
You can avoid the complexity of a uasort() call if you just position your columns in the order that you want to alphabetize them. This method has the added benefit of sorting all column data from left to right. This means, regardless of sorting direction (asc or desc), my method will sort $rows[0], then $row[1], then $row[2], then $row[3].
I have also logically combined your two if statements and set ASC as the default sorting direction.
Code: (Demo)
$txt=['9999|Marco|markkkk998|355647689','1|Marco|markkkk998|355647689','3692|Giovanni|giojo982|0005405','9797|Stefano|stefy734|45367','2566|Marco|markkkk998|355647689','4721|Roberto|robn88|809678741'];
foreach($txt as $row){
$values=explode('|',$row);
$rows[]=[$values[1],$values[0],$values[2],$values[3]]; // just reposition Name column to be first column
}
if(isset($_GET['Z-A'])) {
arsort($rows); // this will sort each column from Left-Right using Z-A
}else{
asort($rows); // (default) this will sort each column from Left-Right using A-Z
}
// var_export($rows);
foreach($rows as $i=>$profile) {
echo "$i {$profile[0]}\n"; // name value
}
Output:
2 Giovanni
1 Marco
4 Marco
0 Marco
5 Roberto
3 Stefano
If I understood your question, you could try this function:
function sortValuesKeepKey($lines) {
//declare arrays to be used temporarily
$idNumbers = array();
$values = array();
$return = array();
//loop through each line and seperate the number at the beginning
//of the string from the values into 2 seperate arrays
foreach($lines as $line) {
$columns = explode("|", $line);
$id = array_shift($columns);
$idNumbers[] = $id;
$values[] = implode("|", $columns);
}
//sort the values without the numbers at the beginning
asort($values);
//loop through each value and readd the number originally at the beginning
//of the string
foreach($values as $key => $value) {
//use $key here to ensure your putting the right data back together.
$return[$key] = $idNumbers[$key]."|".$values[$key];
}
//return finished product
return $return;
}
Just pass it the lines as an array and it should return it ordered properly.
If you want to sort the values by name_surname, see the below code
$db_friends = "db_friends.txt";
$dblines = file($db_friends);
// loop the lines
foreach($dblines as $key => $profile) {
// explode each line with the delimiter
list($uni_id, $name_surname, $textnum_id, $num_id) = explode("|", $profile);
// create an array with name_surname as a key and the line as value
$array[$name_surname] = $profile;
}
// bases on the GET paramater sort the array.
if(isset($_GET['A-Z'])) {
ksort($array); //sort acceding
}
if(isset($_GET['Z-A'])) {
krsort($array); // sort descending
}
// loop the sorted array
foreach($array as $key => $value) {
echo $key; // display the name_surname.
}

How to create an array of arrays from another array filtering it by a specific key of the subarrays?

I have following array of arrays:
$array = [
[A,a,1,i],
[B,b,2,ii],
[C,c,3,iii],
[D,d,4,iv],
[E,e,5,v]
];
From this one, I would like to create another array where the values are extract only if the value of third key of each subarray is, for example, greater than 3.
I thought in something like that:
if $array['2'] > 3){
$new_array[] = [$array['0'],$array['2'],$array['3']];
}
So in the end we would have following new array (note that first keys of the subarrays were eliminate in the new array):
$new_array = [
[D,4,iv],
[E,5,v]
];
In general, I think it should be made with foreach, but on account of my descripted problem I have no idea how I could do this. Here is what I've tried:
foreach($array as $value){
foreach($value as $k => $v){
if($k['2'] > 3){
$new_array[] = [$v['0'], $v['2'], $v['3']];
}
}
}
But probably there's a native function of PHP that can handle it, isn't there?
Many thanks for your help!!!
Suggest you to use array_map() & array_filter(). Example:
$array = [
['A','a',1,'i'],
['B','b',2,'ii'],
['C','c',3,'iii'],
['D','d',4,'iv'],
['E','e',5,'v']
];
$newArr = array_filter(array_map(function($v){
if($v[2] > 3) return [$v[0], $v[2], $v[3]];
}, $array));
print '<pre>';
print_r($newArr);
print '</pre>';
Reference:
array_map()
array_filter()
In the first foreach, $v is the array you want to test and copy.
You want to test $v[2] and check if it match your condition.
$new_array = [];
foreach($array as $v) {
if($v[2] > 3) {
$new_array[] = [$v[0], $v[2], $v[3]];
}
}

Keys in PHP array are not sorted numerically

I have a PHP array with keys that contain a year and week number like so:
year-week
Using the built in ksort function it's returning them like so:
ksort($array);
2011-21
2011-3
2011-44
2011-45
Is it possible to have them sorted numerically like so:
2011-3
2011-21
2011-44
2011-45
If you are using PHP >= 5.4 use ksort($array, SORT_NATURAL);
Use uksort to sort the keys, and in the callback use, strnatcmp.
uksort($array, function($a,$b){
return strnatcmp($a,$b);
});
You can use natsort
$a = array_keys($myarray);
// $a now has
// array('2011-21', '2011-3', '2011-45', '2011-44');
natsort($a);
This prints
2011-3
2011-21
2011-44
2011-45
You can then use the $a array as a reference to each element of the array that holds the data (in the example above $myarray)
You can use ksort with natural flag. (Only PHP 5.4+ supports)
ksort($array, SORT_NATURAL);
You'll get the result you want if you format them with a 2 digit week. Something more like 2011-03. See sprint_f().
I see much simpler solutions are available, but here was my initial thought:
function cmp($a, $b) {
$comp1 = explode('-', $a);
$comp2 = explode('-', $b);
$year1 = (int) $comp1[0];
$year2 = (int) $comp2[0];
$week1 = (int) $comp1[1];
$week2 = (int) $comp2[1];
if ($year1 == $year2 && $week1 == $week2) {
return 0;
} elseif ($year1 == $year2) {
return ($week1 < $week2) ? -1 : 1;
} else {
return ($year1 < $year2) ? -1 : 1;
}
}
$array = array('2011-21', '2011-3', '2011-44', '2011-45');
uasort($array, 'cmp');

php arrays sorting contained values

Ok, first of all, I'm not even sure the title is right, if so, I'm sorry.
I have this loop here which is the result of a MongoDB query:
foreach($cursor as $obj) {
$monster = $obj["type"];
$strenght = $obj["strenght"];
$obj["value"] = rand(5, 15);
}
now, I have put rand there to signify that value changes for each iteration. Now i want that this array, when is printed, is ordered by that $obj["value"], and be able to chose if ascending or descending.
ok, I have tried this
foreach($cursor as $obj) {
$type = $obj["monster"];
$strenght = $obj["strenght"];
$obj["value"] = rand(5, 15);
$newarr[] = $obj;
}
usort($newarr, "cmp");
function cmp($a, $b)
{ return $b['value'] < $a['value']; }
foreach ($newarr as $obj)
{
echo $obj['value'] . $obj['type'] . "<br/>";
}
As I expected, the
$obj["value"] = rand(5, 15);
does not get lost at every iteration in fact, the $newarr contains that value, the problem is that it does not sort them at all. The items are printed in the same order as they were put inside the array. Any help?
Thanks
function mysort ($arr,$d='asc') {
global $dir;
$dir = $d;
uasort($arr, 'cmp');
return ($arr);
}
function cmp ($a, $b) {
global $dir;
if($a['value'] == $b['value']) return 0;
else {
if(strtolower($dir) == 'asc')
return ($a['value'] > $b['value']) ? 1 : -1;
else if(strtolower($dir) == 'disc')
return ($a['value'] > $b['value']) ? -1 : 1;
}
}
print_r(mysort($obj, 'disc'));
ACCORDING TO YOUR UPDATE
try this cmp()
function cmp($a, $b) {
if($a['value'] == $b['value']) return 0;
return $a['value'] > $b['value'] ? 1 : -1;
}
First of all, by doing $obj["value"] = rand(..) you are assigning same array variable with different values multiple times. By the end of the loop, the variable will only contain one value.
You probably were trying to do this
$obj["value"][] = rand(5, 15); //This adds a new random item to the array contained in $obj['value'] each time
When you have an array items, you can sort them by using sort()[ascending] function rsort()[Descending[
$sorted = sort($obj["value"]);
print_r($sorted);
You loose this value
$obj["value"] = rand(5, 15);
at each iteration i guess. Check this link for php foreach loop:
PHP FOREACH
For sorting u can use sort function of php:
PHP SORT
Your foreach will not really generate anything useful. So I created an example array to illustrate the principle:
$array = array(
array(
'type' => 'type a',
'strength' => '10',
'value' => '12',
),
array(
'type' => 'type b',
'strength' => '12',
'value' => '15',
),
array(
'type' => 'type c',
'strength' => '11',
'value' => '6',
),
);
Now you want this multi dimensional array to be sorted by the value, so you would have a list if it was descending order, of type b, type a and then type c.
The function you are looking for is array_multisort(). Here a sample how to use it on this particular instance. First you need to create that sorter array for the function to do it's job. Then just use multisort and you are done.
$sorter = array();
foreach ($array as $key => $row) {
$sorter[$key] = $row['value'];
}
array_multisort($sorter, SORT_DESC, $array);
Now $array has been resorted according to the specifications. Use SORT_ASC to reverse the sorting.
Added code: Just for sake of completeness, here is your foreach code that should technically create what you wanted to in the first place:
$array = array();
foreach($cursor as $obj) {
$row = array();
$row['type'] = $obj['type'];
$row['strength'] = $obj['strenght'];
$row['value'] = rand(5, 15);
$array[] = $row;
}
Also you have a typo in strength :)
Since you are working with integer values, you can simply use this:
usort($newarr, "cmp");
function cmp($a, $b) {
return $b['value'] - $a['value'];
}
It will sort your keys in descending order, if you want to change that to ascending, swap $a and $b.
Sorting functions generally expect the compare function to return a value of 0 if the items are the same, <0 if the first argument is less than the second (whatever less means in the particular case) and >0 if the first argument is greater than the second.
With integer values this can simply be written as $a - $b or $b - $a.

Sort a multi-dimensional array using PHP

My array is created like this:
$c3_array[$c3_count]["box"] = $box;
$c3_array[$c3_count]["subseries"] = $subseries;
$c3_array[$c3_count]["foldertitle"] = $foldertitle;
$c3_array[$c3_count]["uri"] = $uri;
How can I sort the array based on "box" ASC, then based on "foldertitle" ASC?
Thanks!
You could use usort and create your own comparison function. Here is a simple example, that might or might not work, depending on what the actual values in the arrays are, but it should at least give you the idea.
function mysort ($a, $b)
{
if ($a['box'] > $b['box']) return 1;
if ($a['box'] < $b['box']) return -1;
if ($a['foldertitle'] > $b['foldertitle']) return 1;
if ($a['foldertitle'] < $b['foldertitle']) return -1;
return 0;
}
usort($c3_array, 'mysort');
I think array_multisort() is what you need. Check the PHP documentation
Using array_multisort, as in example 3.
$boxes = array();
$foldertitles = array();
foreach($c3_array as $key => $array) {
$boxes[$key] = $array['box'];
$foldertitles[$key] = $array['foldertitle'];
}
array_multisort($boxes, SORT_ASC, $foldertitles, SORT_ASC, $c3_array);

Categories