get value from php multidimensional array - php

In the following array I have the number of days as the first value and the number of hours as the second value:
$myoptions = array (
array("1 day",24),
array("2 days",48),
array("3 days",72)
);
To get the second item from the array, I just do the following:
echo $myoptions[0][1]; // returns 48
So what can I do to search the array index above using one of the value? Let's say I need to know what is the number of hours for array = '3 days'.

You can use array_column like as
echo array_column($myoptions,1,0)['3 days'];//72
Demo

It's not likely that the array you showed us is really what you're after.
PHP's arrays are so-called associative arrays, meaning that you can use anything to index them, not just numbers:
$myoptions = array(
"1 day" => 24,
"2 days" => 48,
"3 days" => 72,
);
So,
echo $myoptions["3 days"]
or
$days = "3 days";
echo $myoptions[$days];
would directly return what you need. Of course, in real life applications, you would need to make sure that your input matches one of the indexes of the array.
Actually, but this is not something we can decide without knowing what you try to accomplish but in most cases you really need the opposite:
$myoptions = array(
24 => "1 day",
48 => "2 days",
72 => "3 days",
);
That is, your program stores and uses the numeric part, the number of hours internally, and whenever you need to display the option it represents to the user, you do the conversion to the human readable format, not the other way around.

There are probably better ways to design that array, but here's a function that should give you what you asked for:
function gethours($x, $myoptions){
foreach($myoptions as $o){
if($o[0] == $x){
return $o[1];
}
}
}
echo gethours('3 days', $myoptions);
If the column you search in is always the same you could just go for an associative array and use that column as array keys.

Related

PHP result from two arrays pairing dates where key is "Y"

I have two array
$array1 = array("2017-12-08","2017-12-09","2017-12-10","2017-12-11","2017-12-12","2017-12-13","2017-12-14","2017-12-15","2017-12-16","2017-12-17","2017-12-18","2017-12-19","2017-12-20","2017-12-21","2017-12-22");
$array2 = array("Y","Y","Y","Y","Y","N","N","N","Y","Y","Y","N","N","Y","Y");
I need the first and last date where the key="Y". Like this:
$result = array("2017-12-08 - 2017-12-12", "2017-12-16 - 2017-12-18", "2017-12-21 - 2017-12-22");
How i can make this?
I have tried with array_combine but after that I do not know how to list the dates pairing.
Moved from answer
Yes this is a good idea, Justinas, but the result is not exactly what i need. Your result give me the first 2017-12-08 and the last 2017-12-22. But i need from all pairs the first and end date, like:
"2017-12-08 - 2017-12-12"
"2017-12-16 - 2017-12-18"
"2017-12-21 - 2017-12-22"
Because i need to insert in the db like
INSERT INTO $table start='firstDate' AND end='lastDate'.
And in this example 3 lines.
First find only array keys that contains value as Y:
$yes = array_filter($array2, function ($yn) {return $yn == 'Y'});
Now do $result = array_intersect_key($array1, $yes) to get dates that has Y in array2.
Finally get first (current($result)) and last end($result) dates.
Example

How to sort an array of Imperial values (inches with fractions)?

I am using the following code to sort the values using native sort algorithm.
usort($this->_items, function($a, $b) { return strnatcasecmp($a['label'], $b['label']);});
But the issue is it is not sorting values properly for the following:
$array=array( '18"', '4"', '18 1/2"', '18 1/4"');
It should sort the values in following order
4"
18"
18 1/4"
18 1/2"
Is there any way I can get this type of sorting with PHP code? Thanks.
Here is a tight little solution (Demo):
$array=array('18 1/2"','18"','4"','18 11/12"','18 1/4"');
foreach($array as $k=>$v){
$copy[$k]=preg_match("/(\d+)\/(\d+)/",$v,$m)?$m[1]/$m[2]+(int)$v:(int)$v;
}
array_multisort($copy,SORT_NUMERIC,$array);
var_export($array);
Output:
array (
0 => '4"',
1 => '18"',
2 => '18 1/4"',
3 => '18 1/2"',
4 => '18 11/12"',
)
foreach() iterates $array and calls preg_match() on each value to generate the $copy array values. If it contains a trailing fraction, then the fraction is converted to decimal format and added to the integer, else the string value is converted to an integer.
Then $copy is used by array_multisort() to sort $array. Done!
Years later, I'd probably use this: (Demo)
$array = [
'18 1/2"',
'18"',
'4"',
'18 11/12"',
'18 1/4"'
];
$asDecimal = preg_replace_callback(
'/(\d+)(?: (\d+)\/(\d+))?"/',
function ($m) {
return $m[1] . (isset($m[3]) ? $m[2] / $m[3] : '');
},
$array
);
var_export($asDecimal);
echo "\n";
array_multisort($asDecimal, SORT_NUMERIC, $array);
var_export($array);
I had a very similar issue today the only difference was the number format was slightly different.
5/8
1-3/4
2-13/54
54/64
and a couple hundred more in this style my regex solution was
preg_match_all("/(^.*?)-?(\d+)\/(\d+)/",$input,$matches)
the main advantage to this over the supplied answer is that the first capture group will always match the whole number and in cases where you would have to supply the previous regex with 0 5/8 or 0-5/8 you can simply let the regex leave the first capture group empty. after that its as simple as
$decimalConversion = $matches[2]/$matches[3]+$matches[1]
If you are curious about $matches[0] that will return all matches. Also whole numbers are not matched by this regex but since you really do not need to do any conversion with these as long as they remain in the array you should still be able to pull a sort correctly.
Also I pulled in array_msort from http://php.net/manual/en/function.array-multisort.php as an easier to read and use alternative to array_multisort
after that I used array_values($array) to reset the keys to the new sort and passed the keys back to magento as the sort_order for the option_id of the value by writing directly to the eav_attribute_option table.

PHP Find Gaps over the course of N years across multiple date ranges

Taking a multidimensional array such as
array(
array('begin' => '2006-01-01', 'finish' => '2006-02-28'),
array('begin' => '2006-03-01', 'finish' => '2006-06-30'),
array('begin' => '2006-08-01', 'finish' => '2007-12-30'),
array('begin' => '2007-01-01', 'finish' => '2016-12-30'),
);
I am trying to figure out the best way to process Nth number of arrays with varying degrees of ranges and overlaps to see if there is an gaps over the course of N years. My current requirement is down to the month. But I simply can not currently wrap my head around this. Without going through a series of nested foreaches that ultimately paint me in a corner and are way to expensive to process on bigger data sets.
This code is hopefully in O(n) and assumes that it's an ordered array as in the example.
I used that this date format can be compared as strings and gives the same result, as if you'd worked with complex date objects.
// $a is your multidimensional array as above
$gap = array();
for($i=1; $i<sizeof($a); $i++){
$gap[$i] = $a[$i-1]['finish'] < $a[$i]['begin'];
}
$gap contains an array or booleans, which indicate at which indexes there is a gap.
I'm not going to suggest an actual implementation, but more a general approach.
You can usually look at this kind of problems two ways:
Make super smart code. Craft an algorithm that recursively merges the ranges that overlaps, leaving you with an array of discrete ranges. You have gaps if you have more than one row in the array, and the gaps are defined between the end of a range and the start of another one. The keyword here is recursively.
Make super dumb code. Build an assoc array with all the months of your interval (that can't be very much, even 10 years is only 120 months) as keys, and "true" as value. Iterate your array, and set the months that appears in a range to "false". Use array_filter and ta-dah! You're left with the months having gaps. The key here is to not use date related functions (they're slow) and instead just go at it arithmetically.
Hope this help putting you on the right track.
Not widely tested and needs some refactoring, but this is the best algorithm I could come up with (I've done something similar with database actually):
define('DAY_SEC', 86400);
$result = [];
foreach ($dates as $date) {
$begin = strtotime($date['begin']);
$finish = strtotime($date['finish']);
$merged = null;
foreach ($result as $idx => $span) {
if ($span['begin'] <= $finish + DAY_SEC && $span['finish'] >= $begin - DAY_SEC) {
if (isset($merged)) {
$min = min($span['begin'], $begin, $result[$merged]['begin']);
$max = max($span['finish'], $finish, $result[$merged]['finish']);
unset($result[$idx]);
} else {
$min = min($span['begin'], $begin);
$max = max($span['finish'], $finish);
$merged = $idx;
}
$result[$merged] = ['begin' => $min, 'finish' => $max];
}
}
if (!isset($merged)) {
$result[] = ['begin' => $begin, 'finish' => $finish];
}
}
foreach ($result as &$span) {
$span['begin'] = date('Y-m-d', $span['begin']);
$span['finish'] = date('Y-m-d', $span['finish']);
}
It will result in array of continuous timespans. It adds timespans one by one and merges them when overlaping with all previously added. If it overlaps more than one period then it merges consecutive matches into the first one.

Best to processing large arrays in PHP with my date wise case

I have a large array in PHP, having near around 168000 keys and values. There is date (Y-m-d) and hour in key and numeric value in value.
So value is just a numeric.
And key is in Y-m-d_H format.
Array looks like following:
$input = array('2008-01-01_00' => 123, '2008-01-01_01' => 456, ...... , '2012-09-22_16' => 789);
I need to find the total of last month, last year, current year, current month and etc.
Which is the best way to find it? Please suggest.
What about this:
$results=array();
foreach ($input as $k=>$v) {
$date=explode('_',$k);
$date=explode('-',$date[0]);
//Store year
$key=$date[0];
if (!isset($results[$key])) $results[$key]=0;
$results[$key]+=$v;
//Store month
$key.='-'.$date[1];
if (!isset($results[$key])) $results[$key]=0;
$results[$key]+=$v;
//Store day
$key.='-'.$date[2];
if (!isset($results[$key])) $results[$key]=0;
$results[$key]+=$v;
}
print_r($results);
Change the keys to ints, e.g.
'2008-01-01_00' -> 2008010100
sort your array with ksort()
Then you can use quicksearch to find something between 2008010100 and 2009010100.
Also, Fastest is to traverse the array once and calculate all the statistics you need.
Break it down into manageable execution units and thread them ...
http://pthreads.org/

array_search() for a value greater than or equal to a number?

I'm trying to figure out how I could search an array so that I can find a key in which has a value of greater than or equal to 1.
For instance:
array_search(>1, $array);
^ Illegal syntax
array_search cannot have conditions as the needle to search for, instead use array_walk(). You can pass a custom function into array_walk and it will perform the function against each element of the array. Something like ..
array_walk($array, 'check_great_than_one_fn');
function check_great_than_one_fn($val)
{
//if($val > 1) do whatever your heart pleases..
}
Read more about it at http://www.php.net/array_walk
Please note: the example I gave is very rudimentary and possibly even incorrect in terms of arguments and logic. It is only to give you an idea about how to go about it. Check the documentation in the link I gave to get a proper idea
I'm using something pretty similar to build an array of week days:
// Set different value to test. 0 = Sunday, 1 = Monday
$start_of_week = 5;
// Build an array, where the values might exceed the value of 6
$days = range( $start_of_week, $start_of_week +6 );
// Check if we find a value greater than 6
// Then replace this and all following vals with an array of values lower than 6
if ( $found_key = array_search ( 7, $days ) )
array_splice(
$days,
$found_key,
7 -$found_key +1,
range( 0, $days[ 0 ] -1 )
);
// Check the days:
var_dump( $days );

Categories