I am working on a php code as shown below in which I to want unset xml elements in php.
I have applied the logic in the following way:
When $a is 4, then it should display 4th item from the top from xml.
When $a is 3, then it should display 3rd item from the top from xml.
When $a is 2, then it should display 2nd item from the top from xml.
When $a is 1. then it should display 1st item from the top from xml.
At this moment, I have set value of a to 4.
$a=4;
if ($a == 1) { // it would not unset item[0] and it should display item[0] (April 5)
for($i = count($xml->channel->item); $i >= 1; $i--){
unset($xml->channel->item[$i]);
}
} else if ($a == 2) { // it would not unset item[1] and it should display item[1] (April 4)
for($i = count($xml->channel->item); $i >= 2; $i--){
unset($xml->channel->item[$i]);
}
unset($xml->channel->item[0]);
} else if ($a == 3) { // it would not unset item[2] and it should display item[2] (April 3)
for($i = count($xml->channel->item); $i >= 3; $i--){
unset($xml->channel->item[$i]);
}
unset($xml->channel->item[0]);
unset($xml->channel->item[1]);
} else if ($a == 4) { // it would not unset item[3] and it should display item[3] (April 2)
for($i = count($xml->channel->item); $i >= 4; $i--){
unset($xml->channel->item[$i]);
}
unset($xml->channel->item[0]);
unset($xml->channel->item[1]);
unset($xml->channel->item[2]);
} else if ($a == 5) { // it would not unset item[4] and it should display item[4] (April 1)
unset($xml->channel->item[0]);
unset($xml->channel->item[1]);
unset($xml->channel->item[2]);
unset($xml->channel->item[3]);
}
The above code is not working properly. All the content is being pulled from this xml http://www.cpac.ca/tip-podcast/jwplayer.xml
I have attached the screenshot with the list of items.
If you want to display the information from a particular element, you can just access it directly by its index, without deleting the other entries. This code will work on the XML downloaded from the URL in your question. Note that xml element arrays are 0-indexed so a value of 2 will get the third entry in the array, so we use $a-1 so that a value of 3 corresponds to the third entry. Also note the slight complexity due to some of the children having a different namespace...
$xml = simplexml_load_string($xmlstr);
$a = 3;
$item = $xml->channel->item[$a-1];
echo "Title: " . $item->title . "\n";
echo "Description: " . $item->description . "\n";
$jw = $item->children('jwplayer', true);
echo "Image: " . $jw->image . "\n";
echo "Source: " . $jw->source->attributes()->file . "\n";
Output:
Title: April 3, 2019
Description: Jody Wilson-Raybould and Jane Philpott are removed from the Liberal Caucus. Gerald Butts submits text messages, and other evidence, to the justice committee. The Environment Commissioner says Canada isn't doing enough to fight climate change.
Image: http://media.cpac.ca/_app_images/tip_player_poster.png
Source: http://www.cpac.ca/tip-podcast/1554286033.mp3
Demo on 3v4l.org
Related
Is it possible to control a for-loop when it reaches a certain condition?
Explanation:
I'm retrieving the folder path to a collection of images from a database: these images are then printed out via a for-loop. What I would need to do is control how these images are displayed on the page (say, 5 images per row).
As of now, the for-loop prints out 40 images in a single row, which makes you scroll to the furthest right of the page.
Is there a solution for controlling the for-loop, as in for instance, after 5 successful loops, echo out a < br >? Here's a vulgar thought:
for ($i = 1; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path']; //since it's an array
echo '<img src="' . $folder_path . '">';
//pseudocode
if ($i == 5) {
echo '<br>';
...continue with the loop
}
}
I know the pseudocode looks crazy, but that's pretty much what I need to do: loop for x amount of instances, add something, then continue.
As per #m69's comment, the best option would be to use the % (modulus) comparison operator. As explained by the PHP docs:
$a % $b returns the remainder of $a divided by $b.
So, in your case:
for ($i = 0; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path']; //since it's an array
echo '<img src="' . $folder_path . '">';
if ($i % 5 == 0) { //do this if $i divided by 5 has a remainder of 0
echo '<br>';
}
}
As a side note, you should set $i to 0 at the beginning of your for loop, assuming $rows is set to the number of rows returned from your query. Setting it to 1 will keep it from iterating through the last row, because $i will == 40 (assuming 40 rows), and so will NOT be < 40.
The same loop. The condition for inserting the is ($i % 5 == 0), which means (if this element is the fifth one of his series) will be useful for you.
<?php
for ($i = 1; $i < $rows; $i++) {
$path = $image[$i];
$folder_path = $path['folder_path'];
echo '<img src="' . $folder_path . '">';
if ($i % 5 == 0) {
echo '<br>';
}
}
I have a problem using tcpdf. A form on my page sends a post variable containing content with <li></li> items.
$fzg_features = '<li>' . $_POST['fzg-features'] . '</li>';
I was able to count all <li> items but i only want to display item 1-10.
Is it possible to index the <li> items with php and manage the output? e.g. 4-6 of all list items?
The problem is the source of $_POST['fzg-features']. It comes from a wp plugin writing the whole content as <li></li> items in an array key as a single string.
When it comes as single string you can explode </li> and then remove <li>.
$pizza = "<li>example</li><li>another example</li>"; // Example string
$pieces = explode("</li>", $pizza); // Make many small pieces
foreach ($pieces as $key => $piece) { // Go through all pieces
if ($key === 9) break; // First key in array is 0, so we limit it to 9.
echo substr($piece, 2); // Remove first 2 characters
}
Great, I stand in your debt. Works fine for me. My main issue was to calculate columns for displaying Car features in tcpdf as a 3 column list. As it is not possible using css this solution worked for me:
$fzg_features = $_POST['fzg-features'];
// $pieces holds the array
$pieces = explode("</li><li>", $fzg_features); // Make many small pieces
foreach ($pieces as $key => $piece) { // Go through all pieces
}
// column calculation
$columns = 3;
$colamount = count($pieces) / $columns;
$colamount1 = ceil($colamount);
$colamount2 = ceil($colamount)*2;
// first column
for ($i = 0; $i <= $colamount1 -1; $i++){
echo '<li>' . $pieces[$i] . '</li>';
};
echo '<br><br>';
// second column
for ($i = $colamount1; $i <= $colamount2 -1; $i++){
echo '<li>' . $pieces[$i] . '</li>';
};
echo '<br><br>';
// third column
for($i = $colamount2; $i <= count($pieces)-1; $i++){
echo '<li>' . $pieces[$i] . '</li>';
};
Thanks a lot for your help.
This is more of a puzzle than anything. I've actually found a solution but it is so slow I thought I lost my internet connection (see below).
Here's the problem:
Let's say I have an array of numbers, like so:
$numbers_array = array(1, 2, 3, 4, 5, 6, 7, 8, 9);
Let's also say that I have a number some numbers, stored in variables like so:
$sum = 15;
$sum2 = 24;
$sum3 = 400;
I am trying to create a function that will return true if any of the numbers in $numbers_array can be added together (each only used once) to form the sums:
function is_summable($array_of_nums, $sum_to_check) {
//What to put here?
}
var_dump(is_summable($numbers_array, $sum));
var_dump(is_summable($numbers_array, $sum2));
var_dump(is_summable($numbers_array, $sum3));
The above should output:
bool(true)
bool(true)
bool(false)
Because 7 + 8 = 15, 7 + 8 + 9 = 24, but no combination of 1-9 can create 200.
Here's my EXTREMELY slow solution:
function is_summable($numbers, $sum) {
//Sort provided numbers and assign numerical keys.
asort($numbers);
$numbers = array_values($numbers);
//Var for additions and var for number of provided numbers.
$total = 0;
$numbers_length = count($numbers);
//Empty var to fill below.
$code = '';
//Loop and add for() loops.
for ($i = 0; $i < $numbers_length; $i++) {
$code .= 'for ($n' . $i . ' = 0; $n' . $i . ' < ' . $numbers_length . '; $n' . $i . '++) {';
if ($i != 0) {
$code .= 'if ($n' . $i . ' != $n' . ($i - 1) . ') {';
}
$code .= '$total += intval($numbers[$n' . $i . ']);';
$code .= 'if ($total == $sum) {';
$code .= 'return true;';
$code .= '}';
}
//Add ending bracket for for() loops above.
for ($l = 0; $l < $numbers_length; $l++) {
$code .= '$total -= intval($numbers[$n' . $i . ']);';
if ($l != 0) {
$code .= '}';
}
$code .= '}';
}
//Finally, eval the code.
eval($code);
//If "true" not returned above, return false.
return false;
}
$num_arr = array(1,2,3,4,5,6,7,8,9);
var_dump(is_summable($num_arr, 24));
http://pastebin.com/1nawuwXK
As always, help is appreciated!!
Your problem is in fact a standard algorithmic problem (as Jon mentioned knapsack problem), more specifically Subset sum problem. It can be solved in polynomial time (have look on wiki page).
Pseudocode:
initialize a list S to contain one element 0.
for each i from 1 to N do
let T be a list consisting of xi + y, for all y in S
let U be the union of T and S
sort U
make S empty
let y be the smallest element of U
add y to S
for each element z of U in increasing order do
//trim the list by eliminating numbers close to one another
//and throw out elements greater than s
if y + cs/N < z ≤ s, set y = z and add z to S
if S contains a number between (1 − c)s and s, output yes, otherwise no
I'm trying to modify a joomla module and I have a small problem (which is not joomla related, thus no code necessary).
I have a foreach loop which has a block of code in it which displays an article. It repeats itself as many times as you set it up in the admin panel. I want to add the feature that makes this module display items on more than 1 column. All I need is the perk, I think I have everything else covered.
Basically how do I modify a simple foreach loop so that it displays articles on more than one column?
Instead of this
a
b
c
d
e
I want this
a ........ d
b ........ e
c
You can get the count of results and work from the middle if you're sticking with tables
$half_count = floor(count($entries) / 2);
for($i=0;$i<$half_count;$i++)
{
echo '<tr>';
echo '<td>' . $entries[$i] . '</td>';
echo '<td>' . (isset($entries[$half_count + $i]) ? $entries[$half_count + $i]: '') . '</td>';
echo '</tr>';
}
Here a simple way to do it :
php > $arr = array(1,2, 3, 4, 5, 6, 7, 8, 9, 10);
php > for ($i=0; $i<count($arr); $i+=2) { print $arr[$i] . "\t" . $arr[$i+1] . "\n"; }
1 2
3 4
5 6
7 8
9 10
As far as I know, you won't be able to do it with a foreach statement but with a for.
For example:
$iterations = (count($array_of_items) % 2) ? (count($array_of_items) / 2) + 1 : count($array_of_items) / 2;
for ($i = 0; $i <= $iterations; $i++) {
if (isset($array_of_items[$i+3]))
echo $array_of_items[$i].'........'.$array_of_items[$i+3];
else
echo $array_of_items[$i];
}
Really simple code without so little info but could make the trick!
Instead of outputting in the for loop, I would create two arrays of the articles in the for loop. Then loop through those arrays to create your columns outside of the main loop.
You have little info in the question, but here's something you could use
$arr = array("a","b","c","d","e","f");
for ($i = 0; $i<count($arr); $i++){
echo $arr[$i]." ". $arr[$i+3] ."\n";
if($i == 2){ break;} //Modify 2 as more alphabets are added
}
Outputs
a d
b e
c f
For a generic solution, assuming a packed array....
function show_table($data, $columns)
{
$items=count($data);
$iters=$items/$columns + ($items % $columns) ? 1 : 0;
for ($y=0; $y<$iters; $y++) {
for ($x=0; $x<$columns; $x++) {
$offset=$y*$columns + $x;
if ($offset<$items) print $data[$offset] . ' ';
}
print "\n";
}
}
Have an $A is the data for pagination:
$A = array(
0=>array(
0=>1,
1=>2
),
1=>array(
0=>3,
1=>5,
2=>2
),
2=>array(
0=>3,
1=>1,
2=>6,
3=>6
)
);
Anybody could help me to get the expected ouput (output this "...." more) the most important ?
.... told that it is still more element need to display next page.
or it the remain element from previous page.
There are 09 elements of $A to display ,So
I set
$show_per_page = 3;
Output (for the first page):
1
2
Total:3
3
....//output this "...." more
Output (for the second page):
....//output this "...." continue from first page
5
2
Total:10
3
.... //output this "...." more
Output (for the third page):
.... //output this "...." continue from second page
1
6
6
Total:16
if I set
$show_per_page = 5;
Output (for the first page):
1
2
Total:3
3
5
2
Total:10
// .... //not output this "...." more now
Output (for the second page):
3
1
6
6
Total:16
if I set
$show_per_page = 9;
OUTPUT:
1
2
Total:3
3
5
2
Total:10
3
1
6
6
Total:16
Currently I am try to do with the function paging_from_multi_arr but I am stuck on how implement to got the expeted result:
// page to show (1-indexed)
// number of items to show per page
function paging_from_multi_arr($display_array, $page){
Global $show_per_page;
$start = $show_per_page * ($page-1);
$end = $show_per_page * $page;
$i = 0;
foreach($display_array as $main_order=>$section){
$total = 0;
foreach($section as $sub_order=>$value){
if($i >= $end){
break 2; // break out of both loops
}
$total += $value;
if($i >= $start){
echo $value.'<br>';
}
$i++;
}
if($i >= $start){
echo 'Total:'.$total.'<br>';
}
if($i >= $end){
break;
}
}
$total = count($display_array, COUNT_RECURSIVE);
// Total numbers of elements in $display_array array.
// See http://php.net/manual/en/function.count.php
if ($end < $total){
echo "...";
}
}
$show_per_page = 5;
paging_from_multi_arr($A,$_GET["page"]);
Do you have any idea with the function here? Or could give the better algorithm?
thanks
This should give you the output you're looking for:
function flatten_display_array($display_array){
$new_array = array();
$count = 0;
foreach($display_array as $main_order => $section){
$total = 0;
foreach($section as $sub_order => $value){
$new_array[] = array('main' => $main_order,
'sub' => $sub_order,
'value' => $value);
$total += $value;
$count++;
}
// Add section's total to final element in section
$new_array[$count-1]['total'] = $total;
}
return $new_array;
}
function paging_from_multi_array($display_array, $page = 1, $show_per_page = 3){
if(isset($_GET['page']) && is_numeric($_GET['page'])){
// Page number set externally
$page = $_GET['page'];
}
if(isset($_GET['per_page']) && is_numeric($_GET['per_page'])){
// Per page set externally
$show_per_page = $_GET['per_page'];
}
$start = $show_per_page*($page-1);
$end = $show_per_page*$page;
// Convert array to useable format
$new_array = flatten_display_array($display_array);
/* Formatting elements */
$top_string = '....'; // Indicator continues is on previous page
$bottom_string = '....'; // Indicator continues on next page
$br = '<br />'; // Line break
$indent = ' '; // Indent of value row
$count = 0;
$string = '';
for($i = $start; $i < $end; $i++){
// Loop through visible range
$string .= $indent.$new_array[$i]['value'].$br;
if(isset($new_array[$i]['total'])){
$string .= 'Total: '.$new_array[$i]['total'].$br;
}
}
// Check previous page
if($start > 0 && $start < count($new_array) && !isset($new_array[$start-1]['total'])){
// Started mid-way through section
$string = $top_string.$br.$string;
}
// Check next page
if($end-1 < count($new_array) && !isset($new_array[$end-1]['total'])){
// Stopped mid-way through section
$string .= $bottom_string.$br;
}
return $string;
}
To use it, just call the paging_from_multi_array() function:
echo paging_from_multi_array($A);
This way, if the page number or the amount to show per page is not set, it will default to the ones set in the first line of paging_from_multi_array() (currently page 1 and 3 per page).
Also, look at the lines under /* Formatting Elements */ to set the elements for the output (eg: the '...' before and after each segment.
Without the "total" calculation, it should be a simple pagination (by merging the sub-arrays and paginate on the big array). But actually, "total" has nothing to do with the pagination itself. So I recommending let's first forget the "total" for paginating, then insert it in approriate place later.
My idea begins with creating a merge-array like this:
$B = array(
0=>1,
1=>2
0=>3,
1=>5,
2=>2
0=>3,
1=>1,
2=>6,
3=>6
}
And another array to keep track of the beginning of each sub-array of $A in the merge-array $B:
$C = {0, 2, 5}
Then I can do the pagination pretty simply as usual. About the "total", we can use the original array A to calculate it, then insert into the approriate position based on C.
For a quick example, at page 2, max-per-page = 3
From B, I get the sub-array B1 : B(offset = 1, max-per-page=3, from B[3] to B[5])
$B1 = {
1=>5,
2=>2,
0=>3
}
Based on $C={0,2,5}, by a simple "for" loop, we can have $C[1] = 2 < 3 < 5 = 5 = $C[2] < length(B), so at here we know that we will show 2 sub-array (A[1] and a[2]); and we must calculate and return total(A[1]) as well.
That's my idea. I think it would make things easier to keep track.