sort() Multidimensional Arrays with change value before - php

I want sorting multidimensional array. But I must to change format value to sorting before then get back format in beginning.
This my array (multidimensional)
$db = [['1','00:01:13.145'], ['2','00:02:19.145'],
['3','00:02:13.235'], ['4','00:01:44.020'],
['5','00:02:25.035'], ['6','00:01:11.031']];
For example can help you to answer, I Know a part how to sorting array time and to get format back again:
This my array (single)
$db2 = ['00:01:13.145','00:02:19.145',
'00:02:13.235','00:01:44.020',
'00:02:25.035','00:01:11.031'];
Function to sorting this
$rep = str_replace(':','', str_replace('.','', $db2));
echo arr($rep);
function arr($array) {
$return = array();
foreach($array as $row) {
$return[] = (int)$row;
sort($return);
}
return $return;
}
The output will be
Array ( [0] => 111031 [1] => 113145 [2] => 144020 [3] => 213235 [4] => 219145 [5] => 225035 )
Second, I know how to get format again, example:
$int = 111031;
$str = substr_replace(substr_replace($int,".",-3,-3),":",-6,-6);
echo substr_replace($str,'00:0',-9,-9);
from (int)111031 the output will be 00:01:11.031
Pleas help me to solve this

This should work for you:
Here we simply use usort() to use our own custom compare function. In this function we first explode() the time by a dot, so we get the time and the milliseconds separately. After this we convert the time into a timestamp with strtotime() and multiply it by 1,000 so we can add the milliseconds to it.
With this we have converted the time into milliseconds and we can simply compare the numbers and sort by the milliseconds.
Code:
<?php
$db = [
['1','00:01:13.145'], ['2','00:02:19.145'],
['3','00:02:13.235'], ['4','00:01:44.020'],
['5','00:02:25.035'], ['6','00:01:11.031']
];
usort($db, function($a, $b){
list($timeOne, $millisecondsOne) = explode(".", $a[1]);
list($timeTwo, $millisecondsTwo) = explode(".", $b[1]);
$millisecondsOne = strtotime($timeOne) * 1000 + $millisecondsOne;
$millisecondsTwo = strtotime($timeTwo) * 1000 + $millisecondsTwo;
if($millisecondsOne == $millisecondsTwo)
return 0;
return $millisecondsOne > $millisecondsTwo ? 1 : -1;
});
print_r($db);
?>

Related

How to associate and filter two related arrays?

I have two arrays and I want to link together when processing them.
$dat = array(
"2020-02-01",
"2020-02-05",
"2020-02-10",
"2020-02-12",
"2020-02-15"
);
$word = array(
"Attend To,Explore,Unaided,dull,bad"
);
//User input
$start = "2020-01-01";
$end = "2020-02-07";
I want the input to affect the second array too, so when the first array gets its result from first 2, then the second array too should have it from the first 2.
//Filter out dates between start and end date
$result = array_filter($dat, function($data_item) use($start, $end) {
return $data_item >= $start && $data_item <= $end;
});
and the result is
Array
(
[0] => 2020-02-01
[1] => 2020-02-05
)
I want it to be able to link $dat and $word so that the result for word too will be
Array
(
[0] => Attend To
[1] => Explore
)
I don't find functional programming to be very readable/attractive for this case. Just use a simple foreach loop and conditionally grab the words related by the shared indices.
Since the two arrays share common indices, it is unnecessary work to combine the two arrays -- just reference the indices.
Code: (Demo)
$dat = ["2020-02-01", "2020-02-05", "2020-02-10", "20-02-12", "2020-02-15"];
$word = ["Attend To,Explore,Unaided,dull,bad"];
$words = explode(',', $word[0]);
//User input
$start = "2020-01-01";
$end = "2020-02-07";
$result = [];
foreach ($dat as $index => $date) {
if ($date >= $start && $date <= $end) {
$result[] = $words[$index];
}
}
var_export($result);
Output:
array (
0 => 'Attend To',
1 => 'Explore',
)
The original keys will be maintained after array_filter, so get the entries for keys that are the same by computing the intersection. It appears that $word is a one element array with a string, so just explode it:
$word_result = array_intersect_key(explode(',', $word[0]), $result);
See a Demo.
If one of the arrays has unique values, you can combine the array and just operate on that.
$comb = array_combine(explode(',', $word[0]), $dat);
$result = array_filter($comb, function($data_item) use($start,$end) {
return $data_item >= $start && $data_item <= $end;
});
This yields:
Array
(
[Attend To] => 2020-02-01
[Explore] => 2020-02-05
)
You can use the array as is or use array_keys to get the keys as the $word array.
If it's not guaranteed to be $word[0] then you can use reset($word) or current($word).
A possible solution assuming that the arrays have the same keys (I changed it to reflect this), is to use the constant ARRAY_FILTER_USE_BOTH to array_filter, so that the key is available in the callback function.
here i fill a second array $result2 with the words while filtering the data (note that things are added in use and $result2 is passed by reference):
$dat = array("2020-02-01","2020-02-05","2020-02-10","20-02-12","2020-02-15");
$word = array("Attend To","Explore","Unaided","dull","bad");
//User input
$start = "2020-01-01";
$end = "2020-02-07";
//Filter out dates between start and end date
$result2 = [];
$result = array_filter($dat, function($data_item, $key) use($start, $end, $word, &$result2) {
if($data_item >= $start && $data_item <= $end){
$result2[$key] = $word[$key];
return true;
}
return false;
}, ARRAY_FILTER_USE_BOTH);
AbraCadaver's answer is perfect fit when only the filtering is needed, but this can be useful in case someone has to do extra operations in the filter callback..

nearest date in php strtotime

I have several date(strtotime) in a Variable and want the first nearest date that is after the specified date(my date) with php. what do i do?
Variable:
$varD = "1481691600,1482642000,1482037200";
my date:
1481778000 => (2016-12-15)
several date(strtotime):
1481691600 => (2016-12-14)
1482642000 => (2016-12-25)
1482037200 => (2016-12-18) //result
result:
1482037200 => (2016-12-18)
$varD = "1481691600,1482037200,1482642000";
$myDate = "1481778000";
After you explode the string of timestamps ($varD), you can filter them and return the minimum value of the result. Here is one way to do that using array_filter and min.
$comp = function($x) use ($myDate) { return $x > $myDate; };
$firstDateAfterYours = min(array_filter(explode(',', $varD), $comp));
But if you already know that the timestamps in the string will be in ascending order, it will probably be faster not to convert the whole thing to an array and sort through it. You can use strtok to go through it piece by piece and just stop as soon as you get to a timestamp larger than your target.
$ts = strtok($varD, ',');
while ($ts !== false) {
$ts = strtok(',');
if ($ts > $myDate) break;
}
$firstDateAfterYours = $ts;

Average from inner array

my task is to calculate average value from an array.
$arrayToTest = [[[1], 1], [[1,3,5,7], 4], [[2,5,4,1,2,3], 2.8],
[[-1,-1,-1,-1,-1], -1], [[4,23,84,12,76,34,-7,-23], 25.375]];
From inner array, so for example [1,3,5,7] and expected value is 4.
I have to use a function, I tried this:
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $case)
foreach ($case as $item)
{
$arraySum = array_sum($item);
$arrayCount = array_count_values($item);
$average = $arraySum / $arrayCount;
return $average;
}
}
but it does not work. I feel I'm doing something wrong with calling the inner array.
Comment:
I assume that you wish to calculate the average values of the innermost arrays.
The solution below returns the average of each array - not the average of all arrays. But - of course you easily could calculate the average of all arrays.
Therefore the function arrayAverage(…) returns an array of average values instead of the average value of (only) the last array.
I declared the input array (arrayToTest) explicitely, for the reason that one can better see the array structure (array of arrays and scalars) like this.
Code:
<?php
$arrayToTest = array (
array(
array(1),
1
),
array(
array(1,3,5,7),
4
),
array(
array(2,5,4,1,2,3),
2.8
),
array(
array(-1,-1,-1,-1,-1),
-1
),
array(
array(4,23,84,12,76,34,-7,-23),
25.375
)
);
echo '<pre>'; print_r($arrayToTest); echo '</pre>';
$average = arrayAvarage ($arrayToTest);
echo '<pre>'; print_r($average); echo '</pre>';
function arrayAvarage ($arrayToTest) {
$result = array();
foreach($arrayToTest as $case) {
foreach ($case as $items) {
if (!is_array($items)) continue;
$result[] = array_sum($items) / count($items);
}
}
return $result;
}
?>
Result:
Array
(
[0] => 1
[1] => 4
[2] => 2.8333333333333
[3] => -1
[4] => 25.375
)
if your array contains internal arrays in the index 0, you can do this by:
function arrayAvarage ($arrayToTest)
{
$out_put_arr = array();
foreach($arrayToTest as $case)
{
$arraySum = array_sum($case[0]);
$arrayCount = array_count_values($case[0]);
$avarage = $arraySum / $arrayCount;
$out_put_arr[]= $avarage;
}
return $out_put_arr;
}
so the loop for the main array, each item in the main array will give you array, and int $case[0] = [1,3,5,7] and $case[1] = 4, also you shouldn't return in for loop because this will return the first average only. so you can declare new array to fill with all averages.
function average($array){
return array_sum($array) / count($array);
}
foreach($arrayToTest as $array){
echo "Average: " . average($array[0]);
}
You should look at the first element of the $case array, which is the actual place where the array with values is situated. Note that you can also use the array_sum function.
Also, you should not return just like that, because that will interrupt the function from doing anything more. So, only return when you really want to do that.
As you already have expected values, I see no reason why your function should return those averages again. Instead it could verify the correctness of these expected values, and return the index of the array when that comparison fails.
function arrayAverage ($arrayToTest)
{
foreach($arrayToTest as $index => $case) {
$average = array_sum($case[0]) / count($case[0]);
if ($average !== $case[1]) {
return $index; // not expected value
}
}
return false; // all averages are equal to expected value
}
So, the above function will return FALSE when all averages are as expected. Otherwise it will return the index of the first mismatch.

PHP Array of Price Ranges - Retrieve the lowest and highest

I'm working with a PHP array that shows a range of prices, where an individual item is in the form of "price from-price to". Here's an example of the array:
Array
(
[0] => $625,000-$700,000
[1] => $550,000-$625,000
[2] => $1,000,000-$1,250,000
[3] => $925,000-$1,000,000
)
I now need to retrieve the lowest and highest price in the array, however as they are a range I first need to pull apart each price in each array item. For example using the above array I would like to be able to return something like this:
$minPrice = 550000;
$maxPrice = 1250000;
I'm new to PHP and completely stumped at this point about how to go about parsing each of the values from each array item then getting the lowest/highest value.
I would put all the normalized prices in an array and use the php max, min functions.
<?php
$ranges = array(
"$625,000-$700,000",
"$550,000-$625,000",
"$1,000,000-$1,250,000",
"$925,000-$1,000,000",
);
$prices = array();
foreach ($ranges as $range) {
$prices = array_merge($prices, explode("-", preg_replace("/[\\$,]/i", "", $range)));
}
$maxPrice = max($prices);
$minPrice = min($prices);
try this:
$array = Array
(
0 => '$625,000-$700,000',
1 => '$550,000-$625,000',
2 => '$1,000,000-$1,250,000',
3 => '$925,000-$1,000,000',
);
$tmp = array();
foreach($array as $key=>$value){
$cleanValue = explode('-', str_replace(array('$',','), array('',''), $value));
foreach($cleanValue as $k=>$v){
$tmp[] = $v;
}
}
$minValue = min($tmp);
$maxValue = max($tmp);
echo $minValue . ' '. $maxValue;
Please refer code below.
First value are exploded to an array and then "$" is removed and then value is converted to integer. Then values are added to array and finally min / max functions are called.
$maxPrice = 0;
$max_curr = 0;
$price_arr = array();
foreach($min_maxs as $min_max){
$min_max_arr = explode("-",$min_max); // string to array
array_walk($min_max_arr,"remove_dollar_commas"); // remove "$"
$price_arr = array_merge($price_arr , $min_max_arr ); // add to final array
}
$maxPrice = max($price_arr); // call max function to get maximum value
$minPrice = min($price_arr); // call min function to get minimum value
function remove_dollar_commas(&$subject){
$subject = intval( str_replace(array("\$",","), "", $subject) );
}

How to split the time from a timestamp from a nested array of result?

I have been doing a project in php and i get a nested array from where i have to extract the values.
Here from this array i have to get only the time from the timestamp i.e from [ArrTime] and [DepTIme]
[Segment] => stdClass Object
(
[WSSegment] => stdClass Object
(
[DepTIme] => 2014-12-10T15:40:00
[ArrTime] => 2014-12-10T18:25:00
[ETicketEligible] => 1
[OperatingCarrier] => HW
)
)
I have being trying to apply the implode function on the timestamp but it is not working for me .
Try this one:
$DeptTime = date('H:i:s',strtotime($yourObject->Segment->WSSegment->DepTIme));
$ArrTime = date('H:i:s',strtotime($yourObject->Segment->WSSegment->ArrTime));
Write a function to retrieve it in php
<?php
$str = '2014-12-10T15:40:00';
function getOnlyTime($str = '') {
$time = '';
if (empty($str)) {
return $time;
}
return substr($str, 11);
}
echo getOnlyTime($yourObject->Segment->WSSegment->DepTIme);
echo getOnlyTime($yourObject->Segment->WSSegment->ArrTime);
?>
Live Example:
http://3v4l.org/1qChm
You could loop through the nested objects and see if the format matches a date. If it does, make an array of the matched elements. You could choose to index the array according to the index where it came from (if that matters later on in your code;
// Starts at "Segment"
foreach ($array as $segment => $item)
{
// Loops through the values of"WSSegment"
foreach ($item as $part => $value)
{
// Checks if the value is a valid date, might need to check type; $value must be a string
if ($date = date_create_from_format('Y-m-d\TH:i:s', $value))
{
// Dump to an array.
$dates[$part][] = $date;
}
}
}
$dates is now an array containing all valid dates in \DateTime format.
Here's another way that I recommend for several reasons. It saves one from having to manually extract the data by using substr() or explode(). The code uses two foreach loops to 'drill down to the desired items, namely the departure and arrival date-time data. If any of the names of the nested objects were to change, the code will still run since it makes use of variables in referring to those entities. Using a DateTime object's format property provides a handy way to access just the time information and you can easily exclude the seconds as the following example illustrates:
<?php
/**
* getTime()
* #param $str - date/time string
* returns time in hours and minutes
**/
function getTime( $str ){
$format = "H:i"; // Hours:Minutes
$timeObj = new DateTime( $str );
return $timeObj->format( $format );
}
foreach( $obj as $nested ) {
foreach( $nested as $n ){
echo 'DEP - ',getTime( $n->DepTime ),"\n";
echo 'ARV - ',getTime( $n->ArrTime ),"\n";
}
}
See http://3v4l.org/IdQN1

Categories