I have this array filled with data from a database
$collectTable1 = array( 'errand' => $interest->errand_id,
'timestamp' => $interest->timestamp,
'type' => $interest->type,
'amount' => $interest->amount
);
$collector[] = $collectTable1;
And i want to rsort the timestamp, like this
$sortTime = rsort($collectedData['timestamp']);
I tried this, and i get this output
function timesort($a, $b) {
return (intval($a['timestamp']) > intval($b['timestamp']));
}
usort($collector, "timesort");
2017-12-01 10:53:26
I tought i would get from the descending date point? Something like
2018-09-04 12:32:16.
My timestamp also contains both unixtimestamp and regular dates like this "
2017-12-01 10:53:26"
I guessing you have array of element in $collector.
If you want to sort those by the timestamp you can use usort
Consider the following example:
$collector = array();
$e1 = array("errand" => 1, "timestamp" => "2017-12-01 10:53:26");
$e2 = array("errand" => 2, "timestamp" => "2018-07-01 10:53:26");
$e3 = array("errand" => 3, "timestamp" => "2018-12-01 10:53:26");
$collector = array($e1, $e2, $e3);
function cmp($a, $b)
{
return (strtotime($a['timestamp']) < strtotime($b['timestamp']));
}
usort($collector, "cmp");
When your timestamp values are in string use strtotime to convert them to EPOC before compare.
Now, the $collector array elements are sorted by the timestamp value.
Output of the code example is:
Array
(
[0] => Array
(
[errand] => 3
[timestamp] => 2018-12-01 10:53:26
)
[1] => Array
(
[errand] => 2
[timestamp] => 2018-07-01 10:53:26
)
[2] => Array
(
[errand] => 1
[timestamp] => 2017-12-01 10:53:26
)
)
Once you have your array:
<?php
$data = [
['timestamp' => '100'],
['timestamp' => '300'],
['timestamp' => '200']
];
usort($data, function($a, $b) {
return $b['timestamp'] <=> $a['timestamp'];
});
var_export($data);
Output:
array (
0 =>
array (
'timestamp' => '300',
),
1 =>
array (
'timestamp' => '200',
),
2 =>
array (
'timestamp' => '100',
),
)
If you have multiple value for all key of associative array $collectTable1 than
foreach($interest as $i){
$collectTable1 = array( 'errand' => array($i->errand_id),
'timestamp' => array($i->timestamp),
'type' => array($i->type),
'amount' => array($i->amount)
);
rsort($collectTable1[‘timestamp’]);
Here collectTable1 is an associative array of one dimensional arrays ie.
$collectTable1[‘timestamp’][0]=firstvalue
$collectTable1[‘timestamp’][1]=secondvalue
And so on
Related
I have an array in PHP code below, and I want to convert this array to be grouped by data value. It's always hard to simplify arrays.
Original array:
Array
(
[0] => Array
(
[date] => 2017-08-22
[AAA] => 1231
)
[1] => Array
(
[date] => 2017-08-21
[AAA] => 1172
)
[2] => Array
(
[date] => 2017-08-20
[AAA] => 1125
)
[3] => Array
(
[date] => 2017-08-21
[BBB] => 251
)
[4] => Array
(
[date] => 2017-08-20
[BBB] => 21773
)
[5] => Array
(
[date] => 2017-08-22
[CCC] => 3750
)
[6] => Array
(
[date] => 2017-08-20
[CCC] => 321750
)
)
Below is my desired array:
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
It is also ok to have empty null value if the data doesn't exist. [BBB] => NULL for 2017-08-22.
Can anybody help? Thanks in advance...
A simple loop should do this..
$group = [];
foreach ($data as $item) {
if (!isset($group[$item['date']])) {
$group[$item['date']] = [];
}
foreach ($item as $key => $value) {
if ($key == 'date') continue;
$group[$item['date']][$key] = $value;
}
}
Here : this should do the work.
$dst_array = array();
foreach ($array as $outerval) {
foreach ($outerval as $key => $innerval) {
if ($key != 'date') {
$dst_array[$outerval['date']][$key] = $innerval;
}
}
}
It iterates through the array and then through the entries in each subarray. Any any that is not a date is assigned in the destination array in the subarray corresponding to its date and with its own current key.
I definitely wouldn't recommend any techniques that involve more than one loop -- this process can certainly be performed in a single loop.
If you like language construct iteration, use a foreach() loop: (Demo)
$result = [];
foreach ($array as $row) {
$date = $row['date'];
unset($row['date']);
$result[$date] = array_merge($result[$date] ?? [], $row);
}
var_export($result);
If you like to use functional programming and fewer global variables, use array_reduce(): (Demo)
var_export(
array_reduce(
$array,
function($accumulator, $row) {
$date = $row['date'];
unset($row['date']);
$accumulator[$date] = array_merge($accumulator[$date] ?? [], $row);
return $accumulator;
},
[]
)
);
These techniques unconditionally push data into the subarray with the key based on the date column value.
The above technique will work consistently even if the order of your subarray elements changes.
The ?? (null coalescing operator) is to ensure that array_merge() always has an array in the first parameter -- if processing the first occurrence of a given date, you simply merge the current iteration's data (what's left of it after unset() removes the date element) with an empty array.
I believe this solution will work for you:
<?php
$array = Array
(
0 => Array
(
'date' => '2017-08-22',
'AAA' => '1231',
),
1 => Array
(
'date' => '2017-08-21',
'AAA' => '1172',
),
2 => Array
(
'date' => '2017-08-20',
'AAA' => '1125'
),
3 => Array
(
'date' => '2017-08-21',
'BBB' => '251'
),
4 => Array
(
'date' => '2017-08-20',
'BBB' => '21773',
),
5 => Array
(
'date' => '2017-08-22',
'CCC' => '3750'
),
6 => Array
(
'date' => '2017-08-20',
'CCC' => '321750'
)
);
echo '<pre>';
$array1 = array('AAA' => null, 'BBB' => null, 'CCC' => null);
$array2 = array();
array_walk($array, function ($v) use (&$array2, $array1) {
$a = $v['date'];
if (!isset($array2[$a])) {
$array2[$a] = $array1;
}
unset($v['date']);
$array2[$a] = array_merge($array2[$a], $v);
});
print_r($array2);
Output
Array
(
[2017-08-22] => Array
(
[AAA] => 1231
[BBB] =>
[CCC] => 3750
)
[2017-08-21] => Array
(
[AAA] => 1172
[BBB] => 251
[CCC] =>
)
[2017-08-20] => Array
(
[AAA] => 1125
[BBB] => 21773
[CCC] => 321750
)
)
check output at: https://3v4l.org/NvLB8
Another approach (quick & dirty) making use of an arrays internal pointer:
$newArray = [];
foreach ($array as $childArray) {
$date = current($childArray);
$value = next($childArray); // this advances the internal pointer..
$key = key($childArray); // ..so that you get the correct key here
$newArray[$date][$key] = $value;
}
This of course only works with the given array structure.
Another perfect usage example for the PHP function array_reduce():
// The input array
$input = array(
0 => array(
'date' => '2017-08-22',
'AAA' => '1231',
),
// The rest of your array here...
);
$output = array_reduce(
$input,
function (array $carry, array $item) {
// Extract the date into a local variable for readability and speed
// It is used several times below
$date = $item['date'];
// Initialize the group for this date if it doesn't exist
if (! array_key_exists($date, $carry)) {
$carry[$date] = array();
}
// Remove the date from the item...
// ...and merge the rest into the group of this date
unset($item['date']);
$carry[$date] = array_merge($carry[$date], $item);
// Return the partial result
return $carry;
},
array()
);
The question is not clear. What is the expected result if one key (AAA f.e) is present on two or more dates? This answer keeps only the last value associated with it.
So I have a 2D array that looks a bit like this:
[0] => Array(
[date] => 23-01-2017
[name] => bbb
[othertext] => text2
)
[1] => Array(
[date] => 23-01-2017
[name] => aaa
[othertext] => text3
)
[2] => Array(
[date] => 24-01-2017
[name] => aaa
[othertext] => text1
)
NOTE: This question is not tagged as MySQL, the database used is MongoDB with the sort type of 'date' => 'asc'.
Currently this is returned from my database sorted by date, but does not take into account the name property. I'd like to now sort this by date, and for entries with the same date to then sort by name.
My current approach is to run an array_multisort on the data:
array_multisort(
$array['date'], SORT_STRING,
$array['name'], SORT_STRING,
$arrayCopy //<--This copy of the array has the full datetime object
);
But this then sorts the date as a string, so in certain scenarios it sorts it incorrectly; e.g. 1st March would go before the 2nd Feb. If putting the month first then again it sorts incorrectly when Dec/Jan dates are sorted.
What's the correct approach to this? I've seen mention of usort(), but I'm unsure how to implement it in this use case. Does array_multisort have functionality for dates?
In your database query:
SELECT * from `your_table_name` order by date asc, name asc;
Maybe this in mongodb:
$cursor->sort(array('date' => 1, 'name' => 1));
See: http://php.net/manual/en/mongocursor.sort.php
No need to do it in php afterwards.
I would strongly suggest doing this via the database.
But if you must use usort or are trying to understand how it works:
$arr = [
[
'date' => '23-01-2017',
'name' => 'bbb',
],
[
'date' => '23-01-2017',
'name' => 'aaa',
],
[
'date' => '24-01-2017',
'name' => 'aaa',
],
];
function cmp($a, $b)
{
$aDate = DateTime::createFromFormat('d-m-Y', $a['date']);
$bDate = DateTime::createFromFormat('d-m-Y', $b['date']);
if ($aDate == $bDate) {
if ($a['name'] == $b['name']) {
return 0;
}
return ($a['name'] < $b['name']) ? -1 : 1;
}
return ($aDate < $bDate) ? -1 : 1;
}
usort($arr, "cmp");
print_r($arr);
http://php.net/manual/en/function.usort.php
Outputs:
[0] => Array
(
[date] => 23-01-2017
[name] => aaa
)
[1] => Array
(
[date] => 23-01-2017
[name] => bbb
)
[2] => Array
(
[date] => 24-01-2017
[name] => aaa
)
With usort-function you could do:
$foo = array(
0 => array(
"date" => "23-01-2017",
"name" => "bbb",
"othertext" => "text2"
),
1 => array(
"date" => "23-01-2017",
"name" => "aaa",
"othertext" => "text3"
),
2 => array(
"date" => "24-01-2017",
"name" => "aaa",
"othertext" => "text1"
)
);
usort($foo, function($a, $b)
{
return $a["date"] === $b["date"] ? strcmp($a["name"], $b["name"]) : strcmp(strtotime($a["date"]), strtotime($b["date"]));
});
var_dump($foo);
I have an associative array having two different prices with the same id.
Let it be...
Array ( [0] => Array ( [price] => 3800 [id] => 400015 )
[1] => Array ( [price] => 3700 [id] => 400015 )
[2] => Array ( [price] => 3300 [id] => 400018 )
[3] => Array ( [price] => 3000 [id] => 400018 )
[4] => Array ( [price] => 3100 [id] => 400020 )
[5] => Array ( [price] => 3400 [id] => 400020 ))
I need to display them as
id:400015, Price=3800-3700
id:400018, Price=3000-3600
id:400020, Price=3100-3400
use below if array_column doesn't support
$arr = Array ( '0' => Array ( 'price' => 3800, 'id' => 400015 ) ,
'1' => Array ( 'price' => 3700, 'id' => 400015 ),
'2' => Array ( 'price' => 3300, 'id' => 400018 ),
'3' => Array ( 'price' => 3000, 'id' => 400018 ),
'4' => Array ( 'price' => 3100, 'id' => 400020 ),
'5' => Array ( 'price' => 3400, 'id' => 400020 ),);
$new_arr =array();
foreach($arr as $key=>$row){
if(isset($new_arr[$row['id']])){
$new_arr[$row['id']]= $new_arr[$row['id']].'-'.$row['price'];
}else{
$new_arr[$row['id']]=$row['price'];
}
}
foreach($new_arr as $key=>$row){
echo 'id:'.$key.', Price = '.$row.'<br>';
}
You can loop array and create new array which will be easy to create output you want to show
$newArray = array();
foreach($main as $key=>$val){
$newArray[$val['id']][] = $val['price'];
}
foreach ($newArray as $key=>$val){
sort($val,1);
echo 'id: '.$key.', Price='.implode('-', $val).'<br/>';
}
Loop over the array and print out the respective id and price. Not too sure what you are doing with the price subtraction but this should give you what you need.
$array = array(array('price'=>3800, 'id'=>40015),
array('price'=>3700 , 'id'=>40001),
array('price'=>3800, 'id'=>400015),
array('price'=>3300 , 'id'=>400018),
array('price'=>3000 , 'id'=>400018),
array('price'=>3100 , 'id'=>400020),
array('price'=>3400 , 'id'=>400020));
asort($array);
foreach ($array as $key => $value)
{
echo 'id: '.$value['id'].', Price='.$value['price'].'<br />';
}
Just to show a little bit of variance, and use a PHP7 feature:
usort($data, function($a, $b) { return $a['price'] <=> $b['price']; });
$maxPrices = array_column($data, 'price', 'id');
usort($data, function($a, $b) { return $b['price'] <=> $a['price']; });
$minPrices = array_column($data, 'price', 'id');
foreach($minPrices as $id => $minPrice) {
echo 'id:', $id, ', Price=', $minPrice, '-', $maxPrices[$id], PHP_EOL;
}
This uses usort() to order the array by maximum price (using the new "spaceship" operator); then array_column() to create an array of id's and max prices, as where there are matching id's then the price will be overridden by the previous values so that only the highest value matching each id remains in the $maxPrices array; then does similarly for minimum values.
Finally the loop iterates over the min array, fetching each id and minimum price in turn, and does an id lookup to get the maximum price to display
Demo
Note that use of the spaceship operator does require PHP7
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));
This question already has answers here:
PHP Sort a multidimensional array by element containing Y-m-d H:i:s date
(11 answers)
Closed 11 months ago.
I have an array like the following:
Array
(
[0] => Array
(
'name' => "Friday"
'weight' => 6
)
[1] => Array
(
'name' => "Monday"
'weight' => 2
)
)
I would like to grab the last values in that array (the 'weight'), and use that to sort the main array elements. So, in this array, I'd want to sort it so the 'Monday' element appears before the 'Friday' element.
You can use usort as:
function cmp($a, $b) {
return $a['weight'] - $b['weight'];
}
usort($arr,"cmp");
Can be done using an anonymous function.
Also if your 'weight' is a string use one of the other returns (see the commented out lines):
<?php
$arr = array(
0 => array (
'name' => 'Friday',
'weight' => 6,
),
1 => array (
'name' => 'Monday',
'weight' => 2,
),
);
// sort by 'weight'
usort($arr, function($a, $b) { // anonymous function
// compare numbers only
return $a['weight'] - $b['weight'];
// compare numbers or strings
//return strcmp($a['weight'], $b['weight']);
// compare numbers or strings non-case-sensitive
//return strcmp(strtoupper($a['weight']), strtoupper($b['weight']));
});
var_export($arr);
/*
array (
0 => array (
'name' => 'Monday',
'weight' => 2,
),
1 => array (
'name' => 'Friday',
'weight' => 6,
),
)
*/
You can also use an anonymous function.
usort($items, function($a, $b) {
return $a['name'] > $b['name'];
});
Agree with usort, I also sometimes use array_multisort (http://ca2.php.net/manual/en/function.usort.php) example 3, sorting database results.
You could do something like:
<?php
$days = array(
array('name' => 'Friday', 'weight' => 6),
array('name' => 'Monday', 'weight' => 2),
);
$weight = array();
foreach($days as $k => $d) {
$weight[$k] = $d['weight'];
}
print_r($days);
array_multisort($weight, SORT_ASC, $days);
print_r($days);
?>
Output:
Array
(
[0] => Array
(
[name] => Friday
[weight] => 6
)
[1] => Array
(
[name] => Monday
[weight] => 2
)
)
Array
(
[0] => Array
(
[name] => Monday
[weight] => 2
)
[1] => Array
(
[name] => Friday
[weight] => 6
)
)
If the filed you sort by is string like title name,
array_multisort + Flags for Natural Sorting and CaseInSensitivity are the way to go:
$sort_by_title = array();
foreach($items as $item) {
$sort_by_title [] = $item['title'];
}
array_multisort($sort_by_title , SORT_ASC, SORT_NATURAL | SORT_FLAG_CASE, $items );
NOTE, if the element you are sorting on is a float like .0534 and .0353 (like for a percentage), then you have to multiply both by 1000. not sure why frankly... it appears that usort seems to compare the integer values.
took me awhile to figure that one out...
and 2 tips that may not be immediately obvious:
if your arrays are objects, you can use return $a->weight - $b->weight of course
if you return $b->weight - $a->weight, it will sort desending.
Here's a cool function that might help:
function subval_sort($a,$subkey,$sort) {
foreach($a as $k=>$v) {
$b[$k] = strtolower($v[$subkey]);
}
if($b)
{
$sort($b);
foreach($b as $key=>$val) {
$c[] = $a[$key];
}
return $c;
}
}
Send in the array as $a the key as $subkey and 'asort' or 'sort' for the $sort variable