PHP preg_match constant output - php

I'm trying to parse out a string that could have multiple values and if one doesn't exist the array is outputting the part I'm looking for up one spot, causing me logic headaches.
What I'm trying to parse: P1DT12H15M, or PT1H5M, or PT15M
Basically it's P(Number of Days) T(Number of Hours)(Number of Minutes). The P and T are constant. Here's the match string I have so far:
'/P([0-9]*?)D?T([1-2]?[0-9]?)H?([1-5]?[0-9]?)M?/'
It pulls everything apart, but the array output is not what I'm looking for.
PT2H gives Array ( [0] => PT2H [1] => [2] => 2 [3] => )
PT2H15M gives Array ( [0] => PT2H15M [1] => [2] => 2 [3] => 15 )
But
PT15M gives Array ( [0] => PT15M [1] => [2] => 15 [3] => )
I need that number to be in position 3, if possible.

$exp = '/P(?:([0-9]+)D)*T(?:([1-2]?[0-9])H)*(?:([1-5]?[0-9])M)*/';
preg_match($exp, 'PT2H15M', $m); print_r($m);
preg_match($exp, 'PT15M', $m); print_r($m);
preg_match($exp, 'P1DT12H15M',$m); print_r($m);
result
Array
(
[0] => PT2H15M
[1] =>
[2] => 2
[3] => 15
)
Array
(
[0] => PT15M
[1] =>
[2] =>
[3] => 15
)
Array
(
[0] => P1DT12H15M
[1] => 1
[2] => 12
[3] => 15
)
So, you can take $P = m[1], $H= m[2], $M = m[3]

Your input strings looks like time interval specifiers. Let the PHP internal class DateInterval parse them then access the properties of [DateInterval] to get the values you need:
$int = new DateInterval('P1DT12H15M');
print_r($int);
produces:
DateInterval Object
(
[y] => 0
[m] => 0
[d] => 1
[h] => 12
[i] => 15
[s] => 0
[weekday] => 0
[weekday_behavior] => 0
[first_last_day_of] => 0
[invert] => 0
[days] =>
[special_type] => 0
[special_amount] => 0
[have_weekday_relative] => 0
[have_special_relative] => 0
)
You can access the properties directly (they are public):
printf("%d days, %d hours, %d minutes\n", $int->d, $int->h, $int->i);
If you need them as array you can even convert $int to an array and use them this way:
$date = (array)$int;
printf("%d days, %d hours, %d minutes\n", $date['d'], $date['h'], $date['i']);
If you insist, you can even emulate the behaviour of the preg_match() you struggle to create:
$string = 'P1DT12H15M';
$interval = new DateInterval($string);
$array = (array)$interval;
$matches = array_merge(array($string), array_slice(array_values($array), 0, 6));
print_r($matches);
displays:
Array
(
[0] => P1DT12H15M
[1] => 0
[2] => 0
[3] => 1
[4] => 12
[5] => 15
[6] => 0
)
(use array_slice(..., 3, 6) to keep only the time components)

Related

How can I loop my array to total the score percentage based on his correct answer?

I have this response
[0] => Array (
[name] => Test
[question_id] => 4
[question_choice_id] => 14
[choice_level] => 0
)
[1] => Array (
[name] => Test
[question_id] => 5
[question_choice_id] => 19
[choice_level] => 0
)
[2] => Array (
[name] => Test
[question_id] => 6
[question_choice_id] => 24
[choice_level] => 0
)
[3] => Array (
[name] => Test
[question_id] => 7
[question_choice_id] => 26
[choice_level] => 0
)
[4] => Array (
[name] => Test
[question_id] => 8
[question_choice_id] => 29
[choice_level] => 1
)
[5] => Array (
[name] => Test
[question_id] => 9
[question_choice_id] => 36
[choice_level] => 0
)
[6] => Array (
[name] => Test
[question_id] => 1
[question_choice_id] => 2
[choice_level] => 0
)
[7] => Array (
[name] => Test
[question_id] => 2
[question_choice_id] => 7
[choice_level] => 0
)
[8] => Array (
[name] => Test
[question_id] => 3
[question_choice_id] => 9
[choice_level] => 0
)
I want to get the percentage of the user with the formula of
Score = the_right_answer / total_count_array * 100
The correct answer has a value of 1 in the choice_level columns
so for my example is, the formula should be
Score = 1/ 9 * 100
How can I get the total from this array?
Once I get the answer I just like to return them to my view.
public function progress(){
$category_id = Session::get('category_id');
$user_set_id = Session::get('user_set_id');
$score = Answer::get_user_score($user_set_id,$category_id);
return view('pages.user.user_progress', [
'name' => '',
'score' => '',
]);
}
Can anyone help me on how to do this properly? any help would be really appreciated.
Based on Score = total count_of_array / the_right_answer * 100:
for total count_of_array could be calculated easily using count($answes)
for calculating the_right_answer, you can use array_map() or manual loop:
$total = count($answers);
$correct = 0;
foreach($answers as $answer){
if($answer['choice_level'] == '1'){
$correct++;
}
}
the snippet above will give you $correct as total correct answer
Now that you have the needed data, you can then do the calculation yourself. However, I would remind you that when the user doesn't have any correct answer, you will face a Division by zero warning. Keep that in mind😉
Since apparently choice_level can only take the values 0 or 1 you can use array_sum to get the number of correct answers. You will need to reduce the response array to just that field first, you can achive that with array_column. So all together:
$score = array_sum(array_column($answers, 'choice_level')) / count($answers) * 100;
for each($arrayname['score'] as $item){
}

PHP fill up array holes

I've got an array with values stored per year, per week, coming from my database. The result might look like this:
Array
(
[2018] => Array
(
[40] => 1
[41] => 1
[47] => 1
[48] => 1
[52] => 1
)
[2019] => Array
(
[1] => 1
[2] => 1
[3] => 1
[4] => 1
)
)
or
Array
(
[2018] => Array
(
[48] => 1
[49] => 1
)
[2019] => Array
(
[3] => 1
[4] => 1
)
)
As you can see there are weeks without data. I would like to fill up the array, so all weeks are there. Taking the last array as demo, the desired result would be:
Array
(
[2018] => Array
(
[40] => 1
[41] => 1
[42] => 0 < added
[43] => 0 < added
[44] => 0 < added
[45] => 0 < added
[46] => 0 < added
[47] => 1
[48] => 1
[49] => 0 < added
[50] => 0 < added
[51] => 0 < added
[52] => 1
)
[2019] => Array
(
[1] => 1
[2] => 1
[3] => 1
[4] => 1
)
)
Array
(
[2018] => Array
(
[48] => 1
[49] => 1
[50] => 0 < added
[51] => 0 < added
[52] => 0 < added
)
[2019] => Array
(
[1] => 1
[2] =>
[3] => 1
[4] => 1
)
)
So, the arrays should:
fill up holes between two (not consecutively) numbers
fill up the year array until the end if there is a next year
fill up the first weeks of a new year if there is a previous year and no data in the first week
How can I achieve this?
I think the most efficient way is to use the union operator. This should do it:
<?php
$data = array(
"2018"=> array(
"40" => 1,
"41" => 1,
"47" => 1,
"48" => 1,
"52" => 1
),
"2019"=> array(
"1" => 1,
"2" => 1,
"6" => 1,
"7" => 1
)
);
foreach($data as $year=>$array){
$keys = array_keys($array);
$min = min($keys); $max = 52;
if(!isset($data[$year+1])){
$max = max($keys);
}
$data[$year] = $data[$year] + array_fill($min,$max-$min+1, 0);
ksort($data[$year]);
}
print_r($data);
?>
Output:
Array
(
[2018] => Array
(
[40] => 1
[41] => 1
[42] => 0
[43] => 0
[44] => 0
[45] => 0
[46] => 0
[47] => 1
[48] => 1
[49] => 0
[50] => 0
[51] => 0
[52] => 1
)
[2019] => Array
(
[1] => 1
[2] => 1
[3] => 0
[4] => 0
[5] => 0
[6] => 1
[7] => 1
)
)
You can use a set of array functions such as array_fill() and array_replace() to achieve this.
See comments for the explanation
$array = [
'2018' => [
'40' => 1,
'41' => 1,
'47' => 1,
'48' => 1,
'52' => 1
],
'2019' => [
'3' => 1,
'4' => 1
],
];
$result = []; // initialize result array
$years = array_keys($array); // Get given years
$first_year = min($years); // Get first year
$last_year = max($years); // Get last year
foreach ($array as $year => $value) { // Loop thru each year array
$weeks = array_keys($value); // Get weeks
$start = 1; // Set first week
$weeknum = 52; // Set number of weeks
if ($year === $first_year) { // If first year, change number of weeks
$start = min($weeks);
$weeknum -= $start - 1; // number of weeks is 52 - the first week number - 1
}
if ($year === $last_year) { // If last year, change number of weeks to last given week
$weeknum = max($weeks); // Weeks will be 1 - last given week
}
$result[$year] = array_replace(array_fill($start, $weeknum, 0), $value);
}
var_dump($result);
The first goal of this is to fill an array base on the year.
If first year, create array with first given week to week 52
If last year, create array with week 1 to last given week
If somewhere in the middle, create array with week 1 to week 52
Then replace with your existing data array with same keys

Validate matching array keys

Given the following arrays how can I elegantly validate that option, price and cost arrays have matching key values?
Array
(
[option] => Array
(
[1] => C
[2] => M
[3] => G
)
[price] => Array
(
[1] => 100
[2] => 200
[3] => 300
)
[cost] => Array
(
[1] => 0
[2] => 0
[3] => 0
)
)
I thought of running a foreach(array as key => values) on each array and sending those values to another array, and then using if(!in_array), but theres got to be a better way to do it.
It sounds like you want the same keys as there is no correlation with the values in the array. If so, you can run a diff on the keys of each sub-array:
if(call_user_func_array('array_diff_key', $array)) {
// not the same keys
} else {
// same keys
}
call_user_func_array() takes the array as an array of arguments and passes each to array_diff_key()
If the result is not empty then there are differences
If the result is empty then there are no differences
I recommend using an array in this way:
Array
(
[option] => Array
(
[C] => Array
(
[price] => 100
[cost] => 0
)
[M] => Array
(
[price] => 200
[cost] => 0
)
[G] => Array
(
[price] => 300
[cost] => 0
)
)
)
PHP Code:
$product = array("option" => array("C" => array("price" => 100, "cost" => 0), "M" => array("price" => 200, "cost" => 0), "G" => array("price" => 300, "cost" => 0)));

2 arrays count how many times id = date

Ive sat with this for a while now, and its getting late.
Im trying to get a top 3 of most sales from last month, and i need to count how many times a id from array 1 is equal to array 2 last month(6 = last atm.) like id 4 = 2, id 7 = 3
It might not be the perfect solution, but im just trying to break it down by my self, so later on 'maybe' problems, will i take care of when i hit the wall,
so please, if anyone can help me here, ill be greatfull.
UPDATE
- I will add the result im looking for here: (sorry i didnt before, it makes it alot easier :-)
- The result below, is because i want the count from 2014-06-01 and up to the last day of that month monly, on array[0][1] under this array, only 6-7-8 is not from 2014-06
Hope it makes a bit more sense now ^^
Array
(
[0] => Array
(
[0] => Array
(
[4] => 2
[7] => 3
[1] => 2
[3] => 2
[9] => 1
[12] => 1
[2] => 1
[13] => 1
)
)
)
Array
(
[0] => Array
(
[0] => Array
(
[0] => 4
[1] => 4
[2] => 7
[3] => 1
[4] => 7
[5] => 7
[6] => 3
[7] => 3
[8] => 4
[9] => 9
[10] => 12
[11] => 2
[12] => 13
[13] => 1
)
[1] => Array
(
[0] => 2014-06-18
[1] => 2014-06-10
[2] => 2014-06-05
[3] => 2014-06-05
[4] => 2014-06-12
[5] => 2014-06-11
[6] => 2013-12-12
[7] => 2014-07-23
[8] => 2014-05-13
[9] => 2014-06-01
[10] => 2014-06-12
[11] => 2014-06-04
[12] => 2014-06-04
[13] => 2014-06-11
)
)
)
I hope that what I understood is what you're really asking for. let's say your array definition is :
$arr = Array
(
0 => Array
(
0 => Array
(
0 => 4,
1 => 4,
2 => 7,
3 => 1,
4 => 7,
5 => 7,
6 => 3,
7 => 3,
8 => 4,
9 => 9,
10 => 12,
11 => 2,
12 => 13,
13 => 1
),
1 => Array
(
0 => "2014-06-18",
1 => "2014-06-10",
2 => "2014-06-05",
3 => "2014-06-05",
4 => "2014-06-12",
5 => "2014-06-11",
6 => "2013-12-12",
7 => "2014-07-23",
8 => "2014-05-13",
9 => "2014-06-01",
10 => "2014-06-12",
11 => "2014-06-04",
12 => "2014-06-04",
13 => "2014-06-11"
)
)
);
If you need to test if the date is lower than 6 month and then put their id, sales and date you need to use this code
$result = [];
$index=0;
foreach ($arr[0][0] as $key => $value)
{
$date1 = new DateTime($arr[0][1][$key]);
$date2 = new DateTime();
$diff = $date1->diff($date2);
$diff = ($diff->format('%y') * 12) + $diff->format('%m');
if($diff<=6)
{
$result[$index]['id'] = $key;
$result[$index]['sales'] = $value;
$result[$index]['date'] = $arr[0][1][$key];
$index++;
}
}
var_dump($result);
array_count_values() will give you the number of times each value appears in array 1.
$count = array_count_values($array[0][0]);
Result:
Array
(
[4] => 3
[7] => 3
[1] => 2
[3] => 2
[9] => 1
[12] => 1
[2] => 1
[13] => 1
)
Then you can use a loop to combine with array 2:
$result = array();
foreach($count as $key=>$val) {
$result[$array[0][1][$key]] = $val;
}
Result:
Array
(
[2014-06-12] => 3
[2014-07-23] => 3
[2014-06-10] => 2
[2014-06-05] => 1
[2014-06-01] => 1
[2014-06-04] => 1
[2014-06-11] => 1
)
See demo

Sorting Multidimensional Array by Specific Key

EDIT: For anyone who might come across this post with a similar problem, It was solved by taking konforce's supplied answer and tweaking around a bit with the custom sorting function:
function cmp($a, $b) {
if ($a[5] == $b[5]) {
return ($a[3] < $b[3]) ? -1 :1;
}
return ($a[5] > $b[5]) ? -1 : 1;
}
Notice $a[5] == $b[5] does not return zero. It was changed to check who has the most losses and then sort it in ASC order. I'm sure you can even keep going and add another if-statement in there in-case they have the same losses.
Lastly, all you do is usort($ARRAY, "cmp"); and finito!!!
Original Post
My apologies for coming up with yet another MD Array sorting question but I'm just not getting it. I've searched aplenty
for a solution and although many sites have provided what seemed like a logical answer I still have not been able to figure it out.
My problem is since I'm still learning its been rather difficult for me to grasp the concept of using usort with a custom comparing
function. Atleast, thats what I have seen the most when others have tried to sort MD Arrays.
I'm working on a small project to sharpen up on my php skills. Its a very basic tournament standings script that holds a team's information within an array. I would like to sort the array by most points($array[X][X][5]).
So the array looks something like this:
Array (
[0] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[1] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
) [3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
I would like to sort it by most points(cell #5), so it would look like this after sorting:
Array (
[0] => Array (
[0] => Array (
[0] => rapha
[1] => 10
[2] => 8
[3] => 1
[4] => 1
[5] => 25
)
)
[1] => Array (
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
)
[2] => Array (
[0] => Array (
[0] => strenx
[1] => 9
[2] => 5
[3] => 1
[4] => 3
[5] => 18
)
)
[3] => Array (
[0] => Array (
[0] => ronald reagan
[1] => 5
[2] => 4
[3] => 0
[4] => 1
[5] => 13
)
)
)
The player with 25 points would be at the top, followed by 18, 18, and lastly 13. Sorry for my earlier post, was having difficulty wording my question correctly. Thanks in advanced!
I think you want something like this:
usort($standings, function($a, $b) { return $b[0][5] - $a[0][5]; });
Or prior to PHP 5.3:
function cmp($a, $b) { return $b[0][5] - $a[0][5]; }
usort($standings, 'cmp');
When using usort, the $a and $b parameters will be one "layer" into the supplied array. So in your case, an example of $a or $b will be:
[0] => Array (
[0] => cooller
[1] => 6
[2] => 6
[3] => 0
[4] => 0
[5] => 18
)
I'm not sure why you have an extra containing array there, but as you can see, you want to sort based on the [0][5] position.
usort($standings[0][0][5], 'cmp') won't work because the first parameter isn't an array to sort, it's just a single number, the points.

Categories