Create / add up array with switch statements - php

For readability and perfomance reasons, I'd like to build up an array with a switch statement instead of if-statements.
Consider the following if-statement:
$size = 2;
$array = array();
if($size >= 1) { array_push($array,'one','foo'); }
if($size >= 2) { array_push($array,'two','bar','barista'); }
if($size >= 3) { array_push($array,'three','zoo','fool','cool','moo'); }
It basically counts up from 1 to $size, it might be more readable and most likely a lot faster with a switch-statment...but how do you construct that ??
$step = 2;
$array = array();
switch($step)
{
case ($step>1): array_push($array,'one','foo');
case ($step>2): array_push($array,'two','bar','barista');
case ($step>3): array_push($array,'three','zoo','fool','cool','moo');
}
I tried leaving out the break, which didn't work - as the manual says:
In a switch statement, the condition is evaluated only once[...].
PHP continues to execute the statements until the end of the switch
block, or the first time it sees a break statement.
Anyway, anyone got an idea how to build up such an array with a switch-statement ??

Surely what you want can be achieved much more easily using
$array=range(1,$size);
Based on further coments and subsequent edits, something like:
$baseArray = $array(array('one'),
array('two','twoA'),
array('three','threeA','threeB'),
array(),
array('five'),
);
$step=2;
$array = array_slice($baseArray,0,$step);
and then flatten $array

Well, a switch statement would look like:
edit: the above doesn't work - let me take a look.
but in this example, you could just do:
$size = 2;
$array = range(1, $size); // Array ( [0] => 1 [1] => 2 )

$valuesIWant = array(1=>'one','two','three','four');
$array = array();
for ($i = $step - 1; $i > 0; $i--) $array[] = $valuesIWant[$i];
$array = array_reverse($array);
So if $step is 2, you get:
Array
(
[0] => one
)
...and if it is 4, you get:
Array
(
[0] => one
[1] => two
[2] => three
)

Related

Which ways to clear array is better in this situation?

I intend to create a multidimensional array through a loop. My idea is that inside the loop function, I would assign elements into a single array, then the single array would assign into another big array before i empty the single array for the next loop process.
E.g.
for($i=0;$i<5;$i++){
$arr1['a'] = $i;
$arr1['b'] = $i+=2;
$arr2[] = $arr; //assign the arr1 into the arr2
$arr1= []; //clear arr1 again for the next looping
}
var_dump($arr2);
And the the result would be:
array (size=2)
0 =>
array (size=2)
'a' => int 0
'b' => int 2
1 =>
array (size=2)
'a' => int 3
'b' => int 5
However I find out that there are actually quite many ways to empty an array and Im not sure about that the way I empty the array is better/more efficient than the other ways such as unset or reinitialize the array like $arr1 = array()in this case. I look through online but there are not much in comparing these ways. Any suggestion to improve the performance on this or this is just as good as other ways? By looking at these:
unset($arr)
$arr = array()
$arr = []
And perhaps other ways?
Instead of making one extra array (smaller array) and then assigning the value to the bigger array, you can do something like this:
for($i=0;$i<5;$i++){
$arr2[$i]['a'] = $i;
$arr2[$i]['b'] = $i+2;
}
var_dump($arr2);
Output:
array (size=2)
0 =>
array (size=2)
'a' => int 0
'b' => int 2
1 =>
array (size=2)
'a' => int 3
'b' => int 5
In this case, you will not need to empty the (smaller) array again and again. Also it will save your memory space as you are using just one array.
If you want to execute a comparison, yo can do it with help of this code.
Ref: https://gist.github.com/blongden/2352583
It would look like so:
<?php
$calibration = benchmark(function() {
for($i=0;$i<5;$i++){
$arr2[$i]['a'] = $i;
$arr2[$i]['b'] = $i+2;
}
});
$benchmark = benchmark(function(){
for($i=0;$i<5;$i++){
$arr1['a'] = $i;
$arr1['b'] = $i+=2;
$arr2[] = $arr1;
$arr1 = [];
}
});
echo "Calibration run: ".number_format($calibration)."/sec\n";
echo "Benchmark run: ".number_format($benchmark)."/sec\n";
echo 'Approximate code execution time (seconds): '.number_format((1/$benchmark) - (1/$calibration), 10);
function benchmark($x)
{
$start = $t = microtime(true);
$total = $c = $loop = 0;
while (true) {
$x();
$c++;
$now = microtime(true);
if ($now - $t > 1) {
$loop++;
$total += $c;
list($t, $c) = array(microtime(true), 0);
}
if ($now - $start > 2) {
return round($total / $loop);
}
}
}
Output for a test run in my env (PHP 7.2.8-1+ubuntu16.04.1+deb.sury.org+1)
Calibration run: 258,534/sec
Benchmark run: 259,401/sec
Approximate code execution time (seconds): -0.0000000129
You will see that the given function by Nikhil is actually faster.
Output for the following function being run:
for($i=0;$i<5;$i++){
$arr2[$i]['a'] = $i;
$arr2[$i]['b'] = $i+2;
}
Calibration run: 209,614/sec
Benchmark run: 209,773/sec
Approximate code execution time (seconds): -0.0000000036
Feel free to play around your own tests

How to implode a generator?

I have a PHP generator which generates some $key => $value.
Is there an "easy" way to implode the values (by passing the generator name)? Or to transform it to an array?
I can do this with a couple of lines of code, but are there some builtins functions to accomplish this?
You can use iterator_to_array function for the same, have a look on below example:
function gen_one_to_three() {
for ($i = 1; $i <= 3; $i++) {
// Note that $i is preserved between yields.
yield $i;
}
}
$generator = gen_one_to_three();
$array = iterator_to_array($generator);
print_r($array);
Output
Array
(
[0] => 1
[1] => 2
[2] => 3
)
One has to keep in mind that
A generator is simply a function that returns an iterator.
For instance:
function digits() {
for ($i = 0; $i < 10; $i++) {
yield $i;
}
}
digits is a generator, digits() is an iterator.
Hence one should search for "iterator to array" functions, to find iterator_to_array (suggested by Chetan Ameta )

Creating a genetics calculator in PHP, issues with wrong results

I'm trying to make a genetic calculator. I have the following code:
<?php
$gene1 = 'BA';
$geneA = array();
$i = 0;
while ($i < strlen($gene1)) $geneA[] = substr($gene1,$i++,2);
$gene2 = 'MSBA';
$geneB = array();
$i = 0;
while ($i < strlen($gene2)) $geneB[] = substr($gene2,$i++,2);
$possabilities = array();
foreach ($geneA as $A) {
foreach ($geneB as $B) {
if ($A === strtoupper($A)) $possabilities[] = $A.$B;
else {
if ($B === strtoupper($B)) $possabilities[] = $B.$A;
else $possabilities[] = $A.$B;
}
}
}
print_r($possabilities);
?>
Which works to a degree, it pairs the genes in the array, however it isn't working properly. This pairing should just return BABA and MSBA. Instead it returns this:
Array ( [0] => BAMS [1] => BASB [2] => BABA [3] => BAA [4] => AMS [5] => ASB [6] => ABA [7] => AA )
Which isn't exactly ideal for my project. I thought a better idea would be to comma separate the genes like this $gene1 = 'BA'; and $gene2 = 'MS,BA'; and run a loop combining each gene that way, but i am unsure on how to do this properly. Can anyone shed some light on the idea at all?
I hope I'm right in assuming that
Genes are always made up of two pairs (MS, but not "M" and "S")
Each member of $geneA should be matched with each member of $geneB
Part 1: Resolving the error
In this case your algorithm for splitting has a serious flaw: It always progresses just for one step in the original string ($gene1 and $gene2)
function getGeneArray($geneString) {
// check the argument for fitting your needs!
if ( strlen($geneString) % 2 == 1 ) {
die('Supplied geneString is not made of pairs!'); // better not die - handle errors according to your application methodology
}
// add additional error-catching (there are only certain possible base-pairs, if something else is found you should reject the string
$genes = array();
$i = 0;
while ( $i < strlen($geneString) )
{
$genes[] = substr($geneString, $i, 2);
$i += 2; // Here is your mistake, you just $i++
}
return $genes;
}
With this little function you a) reduce duplicates in your code and b) get a determined outcome (no wrong genes)
Part 2: Making code document itself
Looking at your code it becomes clear, that uppercase-gene-pairs must come befor lowercase pairs, I try to communicate that with the code by using an extra function with a clear name.
function combinePairs($A, $B) {
// uppercase genes build the string first, which means B must be uppercase to come first and A cant be uppercase
if (strtoupper($A) !== $A && strotoupper($B) === $B) {
return $B.$A;
}
return $A.$B;
}
Part 3: Plugging it together
$geneA = getGeneArray($gene1);
$geneB = getGeneArray($gene2);
$possibilities = array();
foreach ($geneA as $A) {
foreach ($geneB as $B) {
$possibilities[] = combinePairs($A, $B);
}
}
print_r($possibilities);
Final Note
As a programmer you want to cater the needs of your client or input source, so of course you can split your genes with commas. Try to use the format most usable for your application and client input. In this case you could easily optain an array by using explode() (explode in the manual)

Simplifying an array in PHP

I have the following Arrays which I need to define in PHP which I've done in a very basic way:
$ch1 = array("A-MTP-1-1","A-MTP-1-2","A-MTP-1-3","A-MTP-1-4");
$ch2 = array("A-MTP-1-5","A-MTP-1-6","A-MTP-1-7","A-MTP-1-8");
$ch3 = array("A-MTP-1-9","A-MTP-1-10","A-MTP-1-11","A-MTP-1-12");
$ch4 = array("A-MTP-2-1","A-MTP-2-2","A-MTP-2-3","A-MTP-2-4");
$ch5 = array("A-MTP-2-5","A-MTP-2-6","A-MTP-2-7","A-MTP-2-8");
$ch6 = array("A-MTP-2-9","A-MTP-2-10","A-MTP-2-11","A-MTP-2-12");
$ch7 = array("A-MTP-3-1","A-MTP-3-2","A-MTP-3-3","A-MTP-3-4");
$ch8 = array("A-MTP-3-5","A-MTP-3-6","A-MTP-3-7","A-MTP-3-8");
$ch9 = array("A-MTP-3-9","A-MTP-3-10","A-MTP-3-11","A-MTP-3-12");
But I was thinking there must be a simple way of writing this rather than writing out each one but not sure where to start, Would someone be able to point me in the right direction to simplifying this PHP as I will also be repeating it for the above but with B instead of A for each one.
Use range() , array_chunk and extract to get this done
<?php
for ($i = 1; $i <= 3; $i++) { # Pass 3 as you need three sets
foreach (range(1, 12) as $val) { # 1,12 again as per your requirements
$arr[] = "A-MTP-$i-" . $val;
}
}
foreach (array_chunk($arr, 4) as $k => $arr1) { # Loop the array chunks and set a key
$finarray["ch" . ($k + 1)] = $arr1;
}
extract($finarray); # Use the extract on that array so you can access each array separately
print_r($ch9); # For printing the $ch9 as you requested.
Demo
OUTPUT : (Illustration for $ch9 part alone)
Array
(
[0] => A-MTP-3-9
[1] => A-MTP-3-10
[2] => A-MTP-3-11
[3] => A-MTP-3-12
)
After doing that , you can use array_chunk to split the array to length of 4.

Replace non-specified array values with 0

I want to replace all array values with 0 except work and home.
Input:
$array = ['work', 'homework', 'home', 'sky', 'door']
My coding attempt:
$a = str_replace("work", "0", $array);
Expected output:
['work', 0, 'home', 0, 0]
Also my input data is coming from a user submission and the amount of array elements may be very large.
A bit more elegant and shorter solution.
$aArray = array('work','home','sky','door');
foreach($aArray as &$sValue)
{
if ( $sValue!='work' && $sValue!='home' ) $sValue=0;
}
The & operator is a pointer to the particular original string in the array. (instead of a copy of that string)
You can that way assign a new value to the string in the array. The only thing you may not do is anything that may disturb the order in the array, like unset() or key manipulation.
The resulting array of the example above will be
$aArray = array('work','home', 0, 0)
A loop will perform a series of actions many times. So, for each element in your array, you would check if it is equal to the one you want to change and if it is, change it. Also be sure to put quote marks around your strings
//Setup the array of string
$asting = array('work','home','sky','door')
/**
Loop over the array of strings with a counter $i,
Continue doing this until it hits the last element in the array
which will be at count($asting)
*/
for($i = 0; $i < count($asting);$i++){
//Check if the value at the 'ith' element in the array is the one you want to change
//if it is, set the ith element to 0
if ($asting[$i] == 'work' || $asting[$i] == 'home')
$asting[$i] = 0;
}
Here is some suggested reading:
http://www.php.net/manual/en/language.types.array.php
http://www.php.net/manual/en/language.control-structures.php
But if you are struggling on stuff such as looping, you may want to read some introductory programming material. Which should help you really understand what's going on.
A bit other and much quicker way, but true, need a loop:
//Setup the array of string
$asting = array('bar', 'market', 'work', 'home', 'sky', 'door');
//Setup the array of replacings
$replace = array('home', 'work');
//Loop them through str_replace() replacing with 0 or any other value...
foreach ($replace as $val) $asting = str_replace($val, 0, $asting);
//See what results brings:
print_r ($asting);
Will output:
Array
(
[0] => bar
[1] => market
[2] => 0
[3] => 0
[4] => sky
[5] => door
)
An alternative using array_map:
$original = array('work','home','sky','door');
$mapped = array_map(function($i){
$exclude = array('work','home');
return in_array($i, $exclude) ? 0 : $i;
}, $original);
you may try array_walk function:
function zeros(&$value)
{
if ($value != 'home' && $value != 'work'){$value = 0;}
}
$asting = array('work','home','sky','door','march');
array_walk($asting, 'zeros');
print_r($asting);
You can also give array as a parameter 1 and 2 on str_replace...
Just a small point to the for loop. Many dont realize the second comparing task is done every new iteration. So if it was a case of big array or calculation you could optimize loop a bit by doing:
for ($i = 0, $c = count($asting); $i < $c; $i++) {...}
You may also want to see http://php.net/manual/en/function.array-replace.php for original problem unless the code really is final :)
Try This
$your_array = array('work','home','sky','door');
$rep = array('home', 'work');
foreach($rep as $key=>$val){
$key = array_search($val, $your_array);
$your_array[$key] = 0;
}
print_r($your_array);
There are a few techniques on this page that make zero iterated function calls -- which is good performance-wise. For best maintainability, I recommend separating your list of targeted string as a lookup array. By modifying the original array values by reference, you can swiftly replace whole strings and null coalesce non-targeted values to 0.
Code: (Demo)
$array = ['work', 'homework', 'home', 'sky', 'door'];
$keep = ['work', 'home'];
$lookup = array_combine($keep, $keep);
foreach ($array as &$v) {
$v = $lookup[$v] ?? 0;
}
var_export($array);
Output:
array (
0 => 'work',
1 => 0,
2 => 'home',
3 => 0,
4 => 0,
)
You can very easily, cleanly extend your list of targeted strings by merely extending $keep.
If you don't want a classic loop, you can use the same technique without modifying the original array. (Demo)
var_export(
array_map(fn($v) => $lookup[$v] ?? 0, $array)
);
this my final code
//Setup the array of string
$asting = array('work','home','sky','door','march');
/**
Loop over the array of strings with a counter $i,
Continue doing this until it hits the last element in the array
which will be at count($asting)
*/
for($i = 0; $i < count($asting); $i++) {
//Check if the value at the 'ith' element in the array is the one you want to change
//if it is, set the ith element to 0
if ($asting[$i] == 'work') {
$asting[$i] = 20;
} elseif($asting[$i] == 'home'){
$asting[$i] = 30;
}else{
$asting[$i] = 0;
}
echo $asting[$i]."<br><br>";
$total += $asting[$i];
}
echo $total;

Categories