I have a database and perform a SQL-request against it to retrieve data. I use a LIMIT statement in my SQL-request to only retrieve eight rows of the SELECT-ed db-data at a time and the DESC-command to sort the data returned in descending order. More data can then be added in the same fashion via a dedicated load-button that performs an ajax-request.
The arrays in my foreach ($result as $data) have the following structure/key-value-pairs.
print_r($data) shows the following:
Array (
[*keyname0*] => group-id
[*keyname1*] => name of 1st-item
[*keyname2*] => state of 1st-item
[*keyname3*] => 93.42
[*keyname4*] => unit of 1st-item
)
Array (
[*keyname0*] => group-id
[*keyname1*] => name of 2nd-item
[*keyname2*] => state of 2nd-item
[*keyname3*] => 93.12
[*keyname4*] => unit of 2nd-item
)
Array (
[*keyname0*] => group-id
[*keyname1*] => name of 3rd-item
[*keyname2*] => state of 3rd-item
[*keyname3*] => 89.92
[*keyname4*] => unit of 3rd-item
)
Array (
[*keyname0*] => group-id
[*keyname1*] => name of 4th-item
[*keyname2*] => state of 4th-item
[*keyname3*] => 89.70
[*keyname4*] => unit of 4th-item
)
...
My aim is to calculate over the multiple items/arrays that get (dynamically) created by the foreach-loop
The calculation should follow this logic: deduct the value of keyname3 of the 2nd item/array (i. e. 93.12) from the value of keyname3 (i. e. 93.42) of the 1st item/array and so forth (i. e. 2nd from 1st, 3rd from 2nd, 4th from 3rd, 5th from 4th and so forth)
The results for the first arrays displayed above should be accordingly:
93.42 - 93.12 = -0.30
93.12 - 89.92 = -3.20
89.92 - 89.70 = -0.22
...
My attempts
Creating a “shift” in the variable $data with next() or arrray_slice(): $data['keyname3']-array_slice($data['keyname3'], 3, 1). This didnt work.
After that, my theory was to use two variables that derive from different SQL-requests. I used OFFSET in one of my SQL-requests in order to skip the first array. I then created a nested foreach-loop. This returned some valid results (among them my wanted values), but due to the nested foreach, for every iteration of the superordinated foreach it iterated through all values of the subordinate foreach (if that makes sense). By using a break, I was able to at least get the first value right. This was the nearest I could get to what I actually want. This is what the code looked like at this point (divs are wrapped in a foreach like so "foreach($result as $data) :" and ending with "endforeach;"):
<div class="classa">
<div><img class="classb" src="../../../img/test.png" alt="Image"></div>
<div class="classc"><p><?php echo number_format((round($data['keyname3'],2)),2,'.',' ') . " " . $data['keyname6']; ?></p></div>
<div class="classd"><p><?php echo $data['keyname2'] ?></p></div>
</div>
<div class="classe">
<p>
<?php
foreach($resultdiff as $key => $value) {
echo (round($value['keyname3']-$data['keyname3'],2));
if (++$count == 1) break;
}
?>
</p>
</div>
My output
This code in combination with the SQL-request displays eight elements with a picture, the name, the value of the according item and the calculated value in the browser. The 1st element contains the correct calculation for that item and shows the value of -3.50. So far so good. The following items then display a list of values, like the following.
2nd: 0, -3.2, -3.42, -4.99, -5.21, -5.22, -5.43, -5.55
3rd: 3.2, 0, -0.22, -1.79, -2.01, -2.02, -2.23, -2.35
...
The bold values are the correct values for that specific element. When I hit the load-button it really gets queer, because all values are stacked upon the previous. So the nested foreach loop with the separate SQL-request doesnt seem to really work for me! Is there a way to avoid a separate SQL-request with another variable and just use the already existing variable $data for this task?
I am an absolute beginner and not at all sure, whether this is alltogether a totally wrong approach or a possible right track. I would really appreciate if someone could break this issue down for me or nudge me in the right direction. Every help is more than welcome, since this is a must-have for my project.
BTW: I haven't yet looked into alternative options, like using JavaScript. If that might be the more suitable approach to get the wanted result, this would also be fine with me. I am still clinging on to PHP for this issue.
As CBroe stated in the comments, you can just use the key/index in the foreach loop to create the sum
<?php
$data = [
[
'indexname0' => 'group-id',
'indexname1' => 'name of 1st-item',
'indexname2' => 'state of 1st-item',
'indexname3' => 93.42,
'indexname4' => 'unit of 1st-item',
],
[
'indexname0' => 'group-id',
'indexname1' => 'name of 1st-item',
'indexname2' => 'state of 1st-item',
'indexname3' => 93.12,
'indexname4' => 'unit of 1st-item',
],
[
'indexname0' => 'group-id',
'indexname1' => 'name of 1st-item',
'indexname2' => 'state of 1st-item',
'indexname3' => 89.92,
'indexname4' => 'unit of 1st-item',
],
[
'indexname0' => 'group-id',
'indexname1' => 'name of 1st-item',
'indexname2' => 'state of 1st-item',
'indexname3' => 89.70,
'indexname4' => 'unit of 1st-item',
],
];
foreach($data as $index => $value) {
if (!isset($data[$index+1])) continue;
echo $data[$index+1]['indexname3'] - $data[$index]['indexname3'].'<br />';
}
demo
Related
In my eCommerce I have some ways to shop and I want to showing some string depended of every way by which user shops on my site.
I have an array to show for all the ways that the user shops on my site, but these ways come from a separate string with a , separated.
array looks like
$array = [
array(
'userShop' => '1,0,0',
'userId' => 245
),
array(
'userShop' => '1,1,1',
'userId' => 12
),
array(
'userShop' => '0,1,0',
'userId' => 25
)
];
in array index userShop - first INT meaning POS deposit and second INT meaning card deposit and third INT meaning cash deposit. 0 meaning don`t going this way and 1 meaning doing shop by this way
and I want to get output like this:
<p>245</p>
<p>POS</p>
<hr>
<p>12</p>
<p>POS, Cart, Cash</p>
<hr>
<p>25</p>
<p>Cart</p>
<hr>
I can do this with if andelseif for all methods and ways, but it's really boring.
You can apply this foreach loop:
$names = ['POS', 'Card', 'Cash'];
foreach($array as $rec){
$nums = explode(',',$rec['userShop']); // explode
$rnames = [];
foreach ($nums as $ind=>$val){ // check each 1 or 0
if ($val) $rnames[] = $names[$ind]; // fill the names
}
// print result
echo '<p>'.$rec['userId'].'</p>'.PHP_EOL.
'<p>'.join(', ',$rnames).'</p>'.PHP_EOL.
'<hr>'.PHP_EOL;
}
Outputs:
<p>245</p>
<p>POS</p>
<hr>
<p>12</p>
<p>POS, Card, Cash</p>
<hr>
<p>25</p>
<p>Card</p>
<hr>
Demo
Working with an array file with following structure. I know there are additional arrays that need to be inserted under each array 'color'.
$items=array (
0 =>
array (
'color' => 'category_a',
),
1 =>
array (
'book' => 'Gone With The Wind',
'movie' => 'GWTW',
'id'=> 'A100'
),
2 =>
array (
'book' => 'Goldfinger',
'movie' => 'GF',
'id'=> 'A103'
),
3 =>
array (
'color' => 'category_b',
),
4 =>
array (
'book' => 'Across The Great Dvide',
'movie' => 'ATGD',
'id'=> 'B102'
),
5 =>
array (
'book' => 'Goldfinger',
'movie' => 'GF',
'id'=> 'B103'
),
);
Once this array is created, I am using a list to loop thru to verify that each value in the list is placed in each 'color' array as follows
foreach ($controllist as $key=>$value){
foreach($items as $item){
if(in_array($value['book'],$item){
echo "PRESENT IN ARRAY"."<BR>";
}else{
echo "INSERT INTO ARRAY HERE"."<BR>";
}
}
}
For simplicity my controllist looks like
Gone With The wind
Across The Great Divide
Goldfinger
Once complete I should end up with the info for Across The Great Divide inserted into 'color'=> 'category a' as the [2] with Goldfinger moving down one. In 'color'=>category_b' the first array should be Gone With The Wind. Any of the 'color' arrays could be missing an array at any position. To sum it up, need to check for the existence of a value from the list, if not present insert into the array. Other than using the foreach loops shown is there an easier way of doing this? If not how can I get the information inserted into the proper position?
Thanks
EDIT:
I believe the question may not be clear. What I need to do is check for the existence of one array in another. If the value in conrollist is not present in the array, insert an array into the array according the position in the conrollist. The inserted array will have the same structure as the others (I can take care of this part). I am having trouble determining if it exist and if not inserting it. Hope this helps
You might want to be using a for loop instead so you have a pointer on each iteration in order to determine where you are in the array.
foreach($items as $item){
for($i = 0; $i < count($controllist); $i++) {
if(in_array($controllist[$i]['book'],$item){
echo "PRESENT IN ARRAY AT POS ".$i."<BR>";
}else{
$controllist[$i]['book'] = $yourvar;
echo "INSERT INTO ARRAY HERE"."<BR>";
}
}
}
This is driving me mad.. I have a PHP script that returns an array in the form $key => $value and I want to rename the key so that I can display it in a table header. I saw there are several ways of doing this but I'm not sure they are what I need... Either that or I haven't understood the examples correctly which is the likely problem.
Basically my array keys differ each time I iterate over a foreach loop and also some can be blank. How can I get round this?
The first output might look like this:
'_can_chaccess' => false,
'_can_chown' => false,
'_can_delete' => false,
'_can_modify' => false,
'_can_read' => true,
'assigned_to_name_879' => 'Unassigned',
'id' => 1,
'type' => 'Private::Reporting::DataViewModel::DataView_223_42858',
'type_877' => 'Email',
The next run through, I might get this:
'_can_chaccess' => false,
'_can_chown' => false,
'_can_delete' => false,
'_can_modify' => false,
'_can_read' => true,
'assigned_to_name_793' => 'Consultants',
'id' => 1,
'object_reference_794' => 'CASE-1004',
'summary_795' => 'Deployment of New System for HQ (Project)',
'type' => 'Private::Reporting::DataViewModel::DataView_200_42858',
),
As you can see, some keys rename the same e.g. id, type. But the most important ones that I am interested in change each time e.g. Assigned To Name.
Any ideas?
Where do you receive your data from?
You can either somehow modify the source of your data, so if it were a query (what I do not assume here), you have the SELECT ... AS ... statement.
First you do need to know how to interpret the changing keys. If e.g. "assigned_to_name_879" and "assigned_to_name_793" is the same field, you can define a canonical function, which mapps both inputs to a unique output.
The output of the cannonical function and as well the other array keys can serve as keys for an additional array, which contains the table headers of your output.
So your current array is the value's array, and by hand you define a header's array:
array(
'assigned_to_name_879' => 'Name assignment'
);
This dynamic way of storing the table headers in an array only makes sense if you are using the array twice. Otherwise you could simply write the header in the html-code which you do output.
I've managed to figure it out using the below:
$mappings_array = array();
foreach ($report['data'][0] as $key => $value) {
$workbooks->log('Old Key', $key);
preg_match_all('([^_\d]+)', $key, $new_key);
$workbooks->log('New Key', $new_key);
$str = implode(" ", $new_key[0]);
$capitalised = ucwords($str);
array_push($mappings_array,$capitalised);
}
Maybe it's not the best solution but it works :) I get the following output:
> New array: «array (
0 => 'Can Chaccess',
1 => 'Can Chown',
2 => 'Can Delete',
3 => 'Can Modify',
4 => 'Can Read',
5 => 'Id',
6 => 'Total Type',
7 => 'Type',
8 => 'Type',
)
I know how to select one random item from an array, but how about ten random items from an array of, say, twenty items? (In PHP.)
What makes it a little more complicated is that each item actually has two parts: a filename, and a description. Basically, it's for a webpage that will display ten random images each time you reload. The actual format of this data doesn't really matter, although it's simple enough that I'd prefer to contain it in flat-text or even hard code it rather than set up a database. (It's also not meant to change often.)
You could shuffle the array and then pick the first ten elements with array_slice:
shuffle($array);
$tenRandomElements = array_slice($array, 0, 10);
You can select one or more random items from an array using array_rand() function.
If you don't want to shuffle() the entire array (perhaps because your array is relatively large), you can call array_rand() to populate an array of keys then filter the input array using that array of keys.
Code: (Demo)
$input = [
['filename' => 'a.php', 'description' => 'foo'],
['filename' => 'b.php', 'description' => 'fooey'],
['filename' => 'c.php', 'description' => 'bar'],
['filename' => 'd.php', 'description' => 'berry'],
['filename' => 'e.php', 'description' => 'buoy'],
['filename' => 'f.php', 'description' => 'barf'],
['filename' => 'g.php', 'description' => 'food'],
['filename' => 'h.php', 'description' => 'foodie'],
['filename' => 'i.php', 'description' => 'boof'],
['filename' => 'j.php', 'description' => 'boogey'],
['filename' => 'k.php', 'description' => 'fudge'],
['filename' => 'l.php', 'description' => 'fudgey'],
['filename' => 'm.php', 'description' => 'barge'],
['filename' => 'n.php', 'description' => 'buggy'],
['filename' => 'o.php', 'description' => 'booger'],
['filename' => 'p.php', 'description' => 'foobar'],
['filename' => 'q.php', 'description' => 'fubar'],
['filename' => 'r.php', 'description' => 'goof'],
['filename' => 's.php', 'description' => 'goofey'],
['filename' => 't.php', 'description' => 'boofey'],
];
var_export(
array_intersect_key(
$input,
array_flip(
array_rand($input, 10)
)
)
);
The output, you will notice, has only 10 rows of randomly selected data in it.
Different from shuffle(), because $input is nominated first in array_intersect_key(), the "random" items are actually in their original order.
Even if you iterate array_rand()'s returned array with a classic loop, the results will still be ordered by their position in the original array.
Code: (Demo)
$randoms = [];
foreach (array_rand($input, 10) as $key) {
$randoms[] = $input[$key];
}
var_export($randoms);
If the position of the random elements is important, you should call shuffle() on the randomly selected results.
Note that the PHP manual says the following for array_rand():
[array_rand()] uses a pseudo random number generator that is not suitable for cryptographic purposes.
When picking only one entry, array_rand() returns the key for a random entry. Otherwise, an array of keys for the random entries is returned. This is done so that random keys can be picked from the array as well as random values.
If multiple keys are returned, they will be returned in the order they were present in the original array.
Trying to pick more elements than there are in the array will result in an E_WARNING level error, and NULL will be returned.
If you aren't sure how many random items will be selected or how many items are in the array, then use min($yourNumberOfRandomItemsToReturn, count($yourArray)).
An array of arrays in PHP should be a good strategy. You can keep the data for these array in any way you like (hard-coded, XML, etc) and arrange it in the arrays as such:
Array {
Array (item0) { filename,description, weight,...}
Array (item1) { filename,description, weight,...}
Array (item2) { filename,description, weight,...}
}
You can then use the array_rand function to randomly remove items from the array. Creating a weight value for each entry will allow you to pick one entry over another using some sort of priority strategy (e.g. randomly get 2 items from the array, check weight, pick the one with a greater weight and replace the other)
I have some code that sort of does what you ask for. I store a list of sponsorship links in a text file, and pick them at random. But, if I want to skew the set, I use multiple the links ;-)
Sponsors file:
Example
Example
BBC
Google
PHP:
$sponsor_config = 'sponsors.txt';
$trimmed = file($sponsor_config, FILE_IGNORE_NEW_LINES | FILE_SKIP_EMPTY_LINES);
$op = array();
$limit = 20; // insurance
$loops = 0;
$needed = 4;
$op[] = '<div id="sponsorship"><!-- start sponsorship -->';
$selected = array();
while ( (count($selected) < $needed) AND ($loops <= $limit)) {
$choice = rand(0, count($sponsors)-1);
if(!in_array($sponsors[$choice], $selected)) $selected[] = $sponsors[$choice];
$loops++;
}
foreach($selected as $k => $selection) {
$op[] = '<p class="sponsorship bg_'.($k%3+1).'">Click the link below to<br />visit our Site Sponsor:<br />'.$selection.'</p>';
}
$op[] = '</div><!-- end sponsorship -->';
return join("\n",$op)."\n";
V. quick and v.v. dirty... but it works
I have a POST request coming to one of my pages, here is a small segment:
[shipCountry] => United States
[status] => Accepted
[sku1] => test
[product1] => Test Product
[quantity1] => 1
[price1] => 0.00
This request can be any size, and each products name and quantity's key would come across as "productN" and "quantityN", where N is an integer, starting from 1.
I would like to be able to count how many unique keys match the format above, which would give me a count of how many products were ordered (a number which is not explicitly given in the request).
What's the best way to do this in PHP?
Well, if you know that every product will have a corresponding array key matching "productN", you could do this:
$productKeyCount = count(preg_grep("/^product(\d)+$/",array_keys($_POST)));
preg_grep() works well on arrays for that kind of thing.
What Gumbo meant with his "use array instead" comment is the following:
In your HTML-form use this:
<input type="text" name="quantity[]" />
and $_POST['quantity'] will then be an array of all containing all of your quantities.
If you need to supply an id you can also do this:
<input type="text" name="quantity[0]" />
$_POST['quantity][0] will then hold the corresponding quantity.
As mentioned by gumbo you could group all parameters describing one item in its own array which usually makes it easier to iterate them. You may not have control over the POST parameters but you can restructure them like e.g. with
<?php
$testdata = array(
'shipCountry' => 'United States',
'status' => 'Accepted',
'sku1' => 'test1',
'product1' => 'Test Product1',
'quantity1' => '1',
'price1' => '0.01',
'sku2' => 'test2',
'product2' => 'Test Product2',
'quantity2' => '2',
'price2' => '0.02'
);
$pattern = '/^(.*\D)(\d+)$/';
$foo = array('items'=>array());
foreach($testdata as $k=>$v) {
if ( preg_match($pattern, $k, $m) ) {
$foo['items'][$m[2]][$m[1]] = $v;
}
else {
$foo[$k] = $v;
}
}
print_r($foo);
Though there be plenty of examples, if you're guaranteed that the numbers should be contiguous, I usually take the approach:
<?php
$i = 1;
while( isset($_POST['product'.$i) )
{
// do something
$i++;
}