How to add many variables vertically for readability in php - php

I have about 45 different values that I need to add, and to avoid having a really long line of variable + variable + variable, I'm looking for a way to add them vertically to make it easier to read.
Only thing I can think of is to load them into an array, but is there a better way?
$variable+
$variable+
$variable+
$variable+

Load them all into an array and then use array_sum

This is pretty dirty, but if you have a common variable name pattern, like the last 6-10 characters as you say. Then you could do this:
$postfixPatterns = array("xxxxxx", "yyyyyy");
$definedVars = get_defined_vars();
$sums = array_combine($postfixPatterns, array_fill(0, count($postfixPatterns), 0));
foreach ($definedVars as $cVarName => $cVar) {
foreach ($postfixPatterns as $cPattern) {
if (preg_match("/" . preg_quote($cPattern, "/") . "$/", $cVarName)) {
$sums[$cVarName] += $cVar;
}
}
}
// var_dump($sums); --> array('xxxxxx' => sum of xxxxxx,
// 'yyyyyy' => sum of yyyyyy);
Of course it would be better to refactor the code to store the values in an array in the first place!

You can also use this syntax :
$sum = $var1;
$sum += $var2;
$sum += $var3;
...

Related

PHP - Stop need to create hundreds of variables

I'm writing a script and it seems like a bit of a ballache so I came on SO to ask for a little help making my script more dynamic so I create a better version of what I'm doing. I've read into variable variables but I'm still stuck on how I'd use them.
I'll obviously shorten this down but my current script is:
$a0 = $tags['items'][0]['snippet']['tags'];
$a1 = $tags['items'][1]['snippet']['tags'];
$a2 = $tags['items'][2]['snippet']['tags'];
if (!is_array($a0)) { $a0 = array(); }
if (!is_array($a1)) { $a1 = array(); }
if (!is_array($a2)) { $a2 = array(); }
$a0 = array_map('strtolower', $a0);
$a1 = array_map('strtolower', $a1);
$a2 = array_map('strtolower', $a2);
array_count_values(array_merge($a0,$a1,$a2));
I'm looking for a way to dynamically create the variables (For example using an index in a while loop rather than creating these variables uniquely. This obviously is fine on a small scale, but i've currently done 50 of these for each and it's causing serious time problems. Any help is much appreciated
Treat the whole $tags variable as an array and you can do this, similar to the strtolower array_map you have already:
$tagItems = [];
foreach($tags['items'] as $item) {
if (!$item['snippet']['tags'] || !is_array($item['snippet']['tags'])) {
continue;
}
foreach($item['snippet']['tags'] as $tag) {
$tag = strtolower($tag);
if (!isset($tagItems[$tag])) {
$tagItems[$tag] = 0;
}
$tagItems[$tag]++;
}
}
As #FranzGleichmann says, try not to use variable variables, which are a smell and potential security risk, but instead rethink how you want to approach the problem.
You should be able to produce the same output that you get from array_count_values with a nested foreach loop.
foreach ($tags['items'] as $x) { // loop over the list of items
foreach ($x['snippet']['tags'] as $tag) { // loop over the tags from each item
$tag = strtolower($tag);
if (!isset($counts[$tag])) $counts[$tag] = 0;
$counts[$tag]++; // increment the tag count
}
}
No need to create 100 variables. That would cause a headache. Instead, use a simple loop function.
$b = array();
for ($n=1; $n<=100; $n++) {
$a = $tags['items']["$n"]['snippet']['tags'];
if (!is_array($a)) { $a = array(); }
$a = array_map('strtolower', $a);
array_count_values(array_merge($b,$a));
}
I hope it works! Have a nice coding
I would write this in a comment but i will a long one,
Variable Variable, is simply the value of the original var assigned as a var name, which means:
$my_1st_var = 'im_1st';
//use $$
$$my_1st_var = 'im_2nd'; //that is the same of $im_1st='im_2nd';
//results
echo $my_1st_var; // >>> im_1st
echo $im_1st; // >>> im_2nd
that means i created a new var and called it the value of the 1st var which is im_1st and that makes the variable name is $im_1st
also you can set multiple values as a var name:
$var0 = 'a';
$var1 = 'b';
$var2 = 'c';
$var3 = '3';
//we can do this
${$var0.$var1} = 'new var 1'; //same as: $ab = 'new var 1';
${$var1.$var2.$var3} = 'im the newest'; //same as: $bc3 = 'im the newest';
//set a var value + text
${$var0.'4'.$var1} = 'new?'; //same as: $a4b = 'new?';
also $GOLBALS[]; is some kind of $$
hope it helps you understanding what is hard for you about $$ ;)
Alright so dynamically creating variables is easy is a script language like PHP.
You could make $a an array, and instead of $a0, $a1, ... use $a[$i] where $i goes from 0 to 50 or more.
Or you could use this nice funky syntax: ${'a'.$i}. For example:
$i = 0;
${'a'.$i} = 'foobar';
echo $a0; // will output foobar
However you shouldn't do any of this.
What you should do is think about what you are trying to achieve and come up with a different algorithm that doesn't require dynamically named variables.
In this case, something like this looks like it would do the job:
$result = [];
foreach ( $tags['items'] as $item ) {
if ( is_array($item['snippet']['tags']) ) {
$result = array_merge($result, array_map('strtolower',$item));
}
}
array_count_values($result);
This is obviously not tested and from the top of my head, but I hope you get the idea. (EDIT: or check the other answers with similarly rewritten algorithms)

php - how to sort all elements of array except one

I am looking for elegant way to sort two of three values stored in one array. The third one can be ignored but i dont want to loose it (so unseting is not an option).
Imagine such array:
$r = Array("tree_type" => 1, "tree_height" = 5, "tree_age" = 2);
If tree_height is bigger then it's age i want to swap tree height with tree_age, so tree height is always smaller number then age.
Now I am sorting it like this:
if ( $r['tree_height'] > $r['tree_age'] ) {
$tmp = $r['tree_height'];
$r['tree_height'] = $r['tree_age'];
$r['tree_age'] = $tmp;
}
It works perfectly fine, but i am looking for more elegant way. The best solution would be sth like this:
fname($r, $r['tree_height'], $r['tree_age']);
fname would always swap second argument with third if it's bigger then third, otherwise would do nothing.
Any advice would be appreciated.
Kalreg.
ANSWER:
The shortest answer, without condition is:
$tmp = Array($r['tree_height'], $r['tree_age'])
sort($tmp);
You could just encase the code into a function:
function swap(&$arr){ //NOTE SIGN & meaning passing by reference.
if ($arr['tree_height'] > $arr['tree_age']){
$cache_age = $arr['tree_age'] ;
$arr['tree_age'] = $arr['tree_height'] ;
$arr['tree_height'] = $cache_age ;
}
}
$r = array("tree_type" => 1, "tree_height" => 5, "tree_age" => 2);
swap($r);
var_dump($r);
Another elegant solution: (based on Is there a PHP function for swapping the values of two variables?)
function swap(&$arr){ //NOTE SIGN & meaning passing by reference.
if ($arr['tree_height'] > $arr['tree_age']){
list($arr['tree_height'], $arr['tree_age']) = array($arr['tree_age'], $arr['tree_height']);
}
}
This might work (not tested):
function fname(&$a, &$b) {
if ($a <= $b)
return;
$t = $a;
$a = $b;
$b = $t;
}
fname($r['tree_height'], $r['tree_age']);
EDIT: Maybe You wanted something like this?
function fname(&$array, $name1, $name2) {
if ($array[$name1] <= $array[$name2])
return;
$t = $array[$name1];
$array[$name1] = $array[$name2];
$array[$name2] = $t;
}
fname($r, 'tree_height', 'tree_age');

Concatenate strings for variable identifier in PHP

I know this is not the proper way to do this, however I am trying to put a quick fix on a form that was done by another developer. Basically I want to add an incremental number to a variable inside a while statement:
$count = 1;
while ($r = mysql_fetch_array($query)) {
$variable . $count = $r['somefield'];
$count++
}
So that makes the variables:
$variable1
$variable2
$variable3
....etc
$varname = 'variable' . $count;
$$varname = $r['somefield'];
http://www.php.net/manual/en/language.variables.variable.php
You'd be better off with an array...
$variable[] = $r['somefield'];
You can use variable variables, however it is probably not a good idea, especially for a trivial case like this one.

Elegant Method of Inserting Code Between Loops

In web development, I often find I need to format and print various arrays of data, and separate these blocks of data in some manner. In other words, I need to be able to insert code between each loop, without said code being inserted before the first entry or after the last one. The most elegant way I've found to accomplish this is as follows:
function echoWithBreaks($array){
for($i=0; $i<count($array); $i++){
//Echo an item
if($i<count($array)-1){
//Echo "between code"
}
}
}
Unfortunately, there's no way that I can see to implement this solution with foreach instead of for. Does anyone know of a more elegant solution that will work with foreach?
I think you're looking for the implode function.
Then just echo the imploded string.
The only more elegant i can think of making that exact algorithm is this:
function implodeEcho($array, $joinValue)
{
foreach($array as $i => $val)
{
if ($i != 0) echo $joinValue;
echo $val;
}
}
This of course assumes $array only is indexed by integers and not by keys.
Unfortunately, I don't think there is any way to do that with foreach. This is a problem in many languages.
I typically solve this one of two ways:
The way you mention above, except with $i > 0 rather than $i < count($array) - 1.
Using join or implode.
A trick I use sometimes:
function echoWithBreaks($array){
$prefix = '';
foreach($array as $item){
echo $prefix;
//Echo item
$prefix = '<between code>';
}
}
If more elaborate code then an implode could handle I'd use a simple boolean:
$looped = false;
foreach($arr as $var){
if($looped){
//do between
}
$looped = true;
//do something with $var
}

What is the best way to ascertain the length (in characters) of the longest element in an array?

What is the best way to ascertain the length (in characters) of the longest element in an array?
I need to find the longest element in an array of option values for a select box so that I can set the width dynamically.
If you just want the highest value:
echo max(array_map('strlen', $arr));
If you want the longest values:
function array_longest_strings(array $arr)
{
$arr2 = array_map('strlen', $arr);
$arr3 = array_intersect($arr2, array(max($arr2)));
return array_intersect_key($arr, $arr3);
}
print_r(array_longest_strings($arr));
I thought I'd write this in a different, and less obvious way, for the hell of it.
No conditionals, understanding how this works, is an exercise left to the reader.
$x = array(
'foo ', 'bar ____' , 'baz', 'q-----------', 'doo'
);
function max_str( $stringArray )
{
$m = '_';
foreach($stringArray as $item )
{
$m[ strlen($item) ] = '_';
}
return strlen( $m );
}
print max_str( $x );
Note: Setting $m to be merely "" doesn't work. Php sucks, and for some reason casts $m into an array. Pure Genius.
Comment Responses
What's the point of not initializing
$m=0 and then in the loop do $m =
max($m, strlen($item))
Because I wanted to be different. That scope of answer had been provided. The Idea here was to try and "visually" processing it, in logical sense, I was trying to get as close as possible to the "print it into a dynamic text box and see how wide the text box is" logic. The only problem here is strings are not 2 dimensional, so vertically stacking the "lines" was as close as I could get. What I really wanted to do is something like
substr( $m , 0 , strlen($item)) = $item;
But php doesn't have LValues, and It would have been complicated and used awful loops to implement that, so I just short-circuited a little with '_' at $length position.
Sure, you may argue this is the wrong approach to the problem, but IMO, what is being attempted and the idea of solving it in PHP is also the wrong approach to the problem, so If I'm going to do something wrong, I may as well be innovatively wrong in ways that possibly expose other weird coding tricks.
Also, as far as I can see your function will be wrong for $stringArray = array("")..
Yes, A minor caveat I must admit, however, if the user has an option box with no strings or all strings being of 0 length, you have a big fail to start with, nobodys going to rightly give a toss that the option box is too large by 5 pixels in this case.
Why its all made of Fail
Realistically, Any algorithm which doesn't have a fully fledged character kerning map correlating pairs of characters to the effective space consumed will be incorrect. You're fine in a monospaced font, but anything else will be hillarious.
iiiiiiiiii
llllllllll
oooooooooo
mmmmmmmmmm
iiiiiiiiii
llllllllll
oooooooooo
mmmmmmmmmm
iiiiiiiiii
llllllllll
oooooooooo
mmmmmmmmmm
10 copies of each, but such space utilization variety!
This returns the key of the longest value and can also give you the value itself
function array_longest_value( $array, &$val = null )
{
$val = null;
$result = null;
foreach( array_keys( $array ) as $i )
{
$l = strlen( $array[ $i ] );
if ( $l > $result )
{
$result = $i;
$val = $array[ $i ];
}
}
return $result;
}
$longval = 0;
$index = -1;
for($i = 0; $i < count($array); $i++) {
if($len = strlen($array[$i]) > $longval) {
$longval = $len;
$index = $i;
}
}
Then you know $array[$index] has the longest element of length $longval
There are two ways of doing that :
Iterate over the whole array and keep the maximum element size ;
Not iterate over the whole array and get the maximum element size from a magic hat :-)
Then, you'll have to know what font you'll be using to display things, and get the caracter sizes, the kernings, and all that things, so that you'll be able to compute the real width of the words which, unless you're using a fixed width font, is not the number of caracters in the string you'll be displaying.
$longest_length = 0;
foreach($array as $key => $value
{
if(isset($value[$longest_length + 1]))
{
$longest_length = strlen($value);
}
}
$array = array('andy', 'patrick', 'mat', 'perenenappels');
function len_sort($a, $b) {
return strlen($a) > strlen($b) ? 1 : 0;
}
usort($array, 'len_sort');
echo array_pop($array);
I believe this is called the high watermark algorithm. O(n) is the best you are going to get for this unless the list is sorted by length already then it would be O(1).
"you can go up on a steep hill in Las Vegas and look West, and with the right kind of eyes you can almost see the high-water mark - the place where the wave finally broke and rolled back." - Dr. Hunter S. Thompson

Categories