Randomizing miltidimentional array - php

I have a 2-dimentional array with 30+ item nodes in the following format.
$catalog= array(
array(
code => "ABC",
name => "Item name",
link => "domain.com/item121"
),
array(
code => "DEF",
name => "Another item name",
link => "domainB.com/item333"
)
);
I need to do the following:
Randomize the array
Display the first 5 items in a row
Display the rest inside another container 5 items per row.
I only want to show complete rows of 5 and no partials. So I count the total items:
$items= count($catalog);
Then I count how many to display to have complete rows of 5:
$showItems = floor($logosN / 5) * 5; // num or rows * cnt per row
I am not sure how to do the rest. I am able to output the items without randomizing
echo '<div class="first5">';
// 5 first items here
echo '</div>';
echo '<div class="restItems">';
// rest items need to go here
for ($x = 0; $x <= $showItems - 1; $x++) {
echo '
<div class="item">
<div class="item_'.$catalog[$x][code].'"></div>
</div>';
}
echo '</div>';
Need some help here. Thanks.

I had a look at the examples posted by the users on the PHP documentation for shuffle and found this function, which if I understand your question correctly does what you want:
Reference: http://www.php.net/manual/en/function.shuffle.php#93214
<?php
function twodshuffle($array)
{
// Get array length
$count = count($array);
// Create a range of indicies
$indi = range(0,$count-1);
// Randomize indicies array
shuffle($indi);
// Initialize new array
$newarray = array($count);
// Holds current index
$i = 0;
// Shuffle multidimensional array
foreach ($indi as $index)
{
$newarray[$i] = $array[$index];
$i++;
}
return $newarray;
}
?>
Please note it only works on two dimensional arrays.
Also, note that it will not shuffle the actual inner array elements, but only shuffle the outer array, if you know what I mean, and if I know what you want ;)

Related

Function returns undefined offset error

I'm trying to resolve the undefined offset. I've Google and looked through stack overflow, but the examples I've found either didn't apply or were too complex for someone of my skill to fathom at this time. I'm very green, but I'd done diligence I promise before asking for help and wisdom.
This is the function as it now exists:
function PrintFolio($aaPh) //aaPh =associative array place holder
{
//print out X number rows of unto 4 images from array with X items
//if array had 7 items, print one row of 4 next row 3
//if array had 16 items, print 4 rows of 4, etc.
//if array had 13 items, print 3 rows of 4, final row with one item
$itemsCount = sizeof($aaPh);//get size of array
$height = (int)ceil(sizeof($aaPh)/4);//rounded up division by 4
//$height = $height + 1;
$keys = array_keys($aaPh); //get keys
//loop through array of X items, for each group of 4 print as a row
for($row = 0; $row < $height; $row++) //looping through the rows
{
echo '<div class="row flush">'; //open div
for($image = 0; $image < 4; $image++) //each row is composed of 4 images
{
$aaPhIndex = array_keys($aaPh)[$row*4+$image]; //if associative array
if( $row*4+$image < $itemsCount ) {
$aaPhIndex = $keys[$row*4+$image];
printf(TEMPLATE_PORTFOLIO, $aaPhIndex, $aaPh[$aaPhIndex]);
//$template = '<div class="3u"><img src="_img/thumbs/%1$s" alt="" title="%2$s" /></div>';
}
}
echo '</div>'; //end div group of 4
}//end loop
}//end function
It takes an array, slices it up in to units of four and then prints the array as a series of images to the screen. But if I don't have a number which is exactly devisable by 4, it will display whatever open slots remain as undefined offset errors (I hope I am saying that correctly).
My goal is to not have the undefined offset errors print to these screen without revising my site error reporting capabilities (I think doing that would be cheating as it wouldn't correct the problem, just hide it which doesn't seem very above board to me).
Why don't you just put a line break after each 4th element?
function PrintFolio($aaPh) //aaPh =associative array place holder
{
//loop through the array
for($row = 0; $row < Count($aaPh); $row++) //looping through the rows
{
if (!$row || !($row%4)) {
if ($row) echo '</div>'; // close previously opened divs
echo '<div class="row flush">'; //open div
}
/* show your picture code here */
}//end loop
echo '</div>';
}//end function
Here is an update after your comments.
Because you do not need values of your associative array, only keys, the code can be changed as follows:
function PrintFolio($aaPh) //aaPh =associative array place holder
{
//loop through the array
$row=0;
foreach(array_keys($aaPh) as $img) //looping through array keys only
{
if (!$row || !($row%4)) {
if ($row) echo '</div>'; // close previously opened divs
echo '<div class="row flush">'; //open div
}
echo '<img src="' . $img . '">';
$row++; // increase row counter.
}//end loop
echo '</div>';
}//end function
Make sure to put proper path into the tag
Since you can't assume that you're always going to have a number of elements that's exactly divisible by four, you need to test each one. In your inner loop where you calculate the index and then use it to refer to the array, just add a check to ensure that array element exists. From this:
$aaPhIndex = $keys[$row*4+$image];
printf(TEMPLATE_PORTFOLIO, $aaPhIndex, $aaPh[$aaPhIndex]);
To this:
$aaPhIndex = $keys[$row*4+$image];
if (isset($aaPh[$aaPhIndex])) {
printf(TEMPLATE_PORTFOLIO, $aaPhIndex, $aaPh[$aaPhIndex]);
}
The error in your logic is that on this line
for($image = 0; $image < 4; $image++) //each row is composed of 4 images
You assume there are always 4 images. But like you said yourself, if the array has for example 13 items, then the last row will only contain one image. This will cause $aaPhIndex = array_keys($aaPh)[$row*4+$image]; to access an array index that doesn't exist.
To solve the problem you will either have to modify $image < 4 to also account for the last row, or just check that the index doesn't exceed the item count. For example by placing the error line under the condition that you already wrote:
if( $row*4+$image < $itemsCount ) {
$aaPhIndex = array_keys($aaPh)[$row*4+$image]; //if associative array
$aaPhIndex = $keys[$row*4+$image];
printf(TEMPLATE_PORTFOLIO, $aaPhIndex, $aaPh[$aaPhIndex]);
//$template = '<div class="3u"><img src="_img/thumbs/%1$s" alt="" title="%2$s" /></div>';
}
Hope this works

PHP - Count all elements of an Array that Satisfy a Condition [duplicate]

This question already has answers here:
Closed 10 years ago.
Possible Duplicate:
Search for PHP array element containing string
I've created a mysql query that pulls through several products, all with the following information:
Product ID
Product Name
Product Price
and
Product Category
Further down the page, I've looped through these with a foreach and a few 'ifs' so it only displays those products where the name contains 'x' in one div and displays those products where the name contains 'y' in another div.
I'm struggling to count how many products are going to be in each div before I do the loop.
So essentially, what I'm asking is:
How do you count all elements in an array that satisfy a certain condition?
Added Code which shows the loop:
<div id="a">
<?php
$i = 1;
foreach ($products AS $product) {
if (strpos($product->name,'X') !== false) {
=$product->name
}
$i++;
} ?>
</div>
<div id="b">
$i = 1;
foreach ($products AS $product) {
if (strpos($product->name,'Y') !== false) {
=$product->name
}
$i++;
} ?>
</div>
I'd like to know how many of these are going to be in here before I actually do the loop.
Well, without seeing the code, so generally speaking, if you're going to split them anyway, you might as well do that up-front?
<?php
// getting all the results.
$products = $db->query('SELECT name FROM foo')->fetchAll();
$div1 = array_filter($products, function($product) {
// condition which makes a result belong to div1.
return substr('X', $product->name) !== false;
});
$div2 = array_filter($products, function($product) {
// condition which makes a result belong to div2.
return substr('Y', $product->name) !== false;
});
printf("%d elements in div1", count($div1));
printf("%d elements in div2", count($div2));
// then print the divs. No need for ifs here, because results are already filtered.
echo '<div id="a">' . PHP_EOL;
foreach( $div1 as $product ) {
echo $product->name;
}
echo '</div>';
echo '<div id="b">' . PHP_EOL;
foreach( $div2 as $product ) {
echo $product->name;
}
echo '</div>';
That being said: you should take notice of the comment which says "This is normally faster in SQL", because it is the more sane approach if you want to filter the values.
EDIT: Changed the name of the variables to adapt the variable names in the example code.
Use an array-filter: http://www.php.net/manual/en/function.array-filter.php
array array_filter ( array $input [, callable $callback = "" ] )
Iterates over each value in the input array passing them to the callback function. If the callback function returns true, the current value from input is returned into the result array. Array keys are preserved.
<?php
function odd($var)
{
// returns whether the input integer is odd
return($var & 1);
}
function even($var)
{
// returns whether the input integer is even
return(!($var & 1));
}
$array1 = array("a"=>1, "b"=>2, "c"=>3, "d"=>4, "e"=>5);
$array2 = array(6, 7, 8, 9, 10, 11, 12);
echo "Odd :\n";
print_r(array_filter($array1, "odd"));
echo "Even:\n";
print_r(array_filter($array2, "even"));
?>
But be aware, this is a loop though, and your the SQL query will be faster.

shift array without indexOfOutBounds

I have 2 array's with the same length. array $gPositionStudents and array $gPositionInternships. Each student is assigned to a different internship, That part works.
Now I want the first element (index 0) of $gPositionStudent refer to the second (index 1) element of array $gPositionInternship. That implicitly means that the last element of $gPositionStudents refer to the first element of $gPositionInternship. (I included a picture of my explanation).
My Code is:
// Make table
$header = array();
$header[] = array('data' => 'UGentID');
$header[] = array('data' => 'Internships');
// this big array will contains all rows
// global variables.
global $gStartPositionStudents;
global $gStartPositionInternships;
//var_dump($gStartPositionInternships);
$rows = array();
$i = 0;
foreach($gStartPositionStudents as $value) {
foreach($gStartPositionInternships as $value2) {
// each loop will add a row here.
$row = array();
// build the row
$row[] = array('data' => $value[0]['value']);
//if($value[0] != 0 || $value[0] == 0) {
$row[] = array('data' => $gStartPositionInternships[$i]);
}
$i++;
// add the row to the "big row data (contains all rows)
$rows[] = array('data' => $row);
}
$output = theme('table', $header, $rows);
return $output;
Now I want that I can choose how many times, we can shift. 1 shift or 2 or more shifts. What I want exists in PHP?
Something like this:
//get the array keys for the interns and students...
$intern_keys = array_keys($gStartPositionInternships);
$student_keys = array_keys($gStartPositionStudents);
//drop the last intern key off the end and pin it to the front.
array_unshift($intern_keys, array_pop($intern_keys));
//create a mapping array to join the two arrays together.
$student_to_intern_mapping = array();
foreach($student_keys as $key=>$value) {
$student_to_intern_mapping[$value] = $intern_keys[$key];
}
You'll need to modify it to suit the rest of your code, but hopefully this will demonstrate a technique you could use. Note the key line here is the one which does array_unshift() with array_pop(). The comment in the code should explain what it's doing.
I think you want to do array_slice($gPositionsStudents, 0, X) where X is the number of moves to shift. This slices of a number of array elements. Then do array_merge($gPositionsStudents, $arrayOfSlicedOfPositions); to append these to the end of the original array.
Then you can do an array_combine to create one array with key=>value pairs from both arrays.

php: add array placement number to each array set e.g. 1 2 3

I have a data set from mysql in a multidimensional array.
I am using a pagination script to show 10 per page of that array. I want to know how to append a number to each one like a scoring system. The array is sorted by the way that it will aways be so i want to to add a 1 to the first item, a 2 to the second item and so on.
I dont want to do this in the foreach that i output since this will not translate over to the second page where it would start back at 1.
Any ideas on how to attach a number in desc order to each item in the array so i can access it in the foreach and display it?
Thanks in advance
Use the same math used to find the offset in your pagination query and start counting from there.
fist you need to save the indexes in a $_SESSION variable:
$_SESSION['indexes'] = array();
and for multidimentional:
foreach( $array as $index=>$arrValue) {
echo $index;
foreach($arrValue as $index2=>$value){
echo $index2;
$_SESSION['indexes'][$index][$index2] = $value;
echo $value;
}
}
than you can go through all of the session indexes; where $index is the page or $index2 can be the row
I figured it out by doing some calculations based on which page i was on and the page count that was set and finding the size of the array from the db:
$all_members = get_users_ordered_by_meta('metavalue', 'desc');
$array_count = count($all_members);
$posts_per_page = get_option('posts_per_page');
if ($page > 0) {
$total_posts_avalible = ($posts_per_page * $page);
$usernum = $total_posts_avalible - $posts_per_page;
}
Then i echo the $usernum in the foreach next to the name of the user.
foreach() {
$usernum++;
echo $usernum; echo $user_name;
}

Pairing Links with PHP Randomized Ads

So I have the following code with works great for randomly generating position for 5 different sidebar ads, my problem is how to give the ads a link that will always be paired with them.
I'm looking for suggestions from some PHP gurus as to best practices for doing this...
<ul class="top_ads">
<?php
$totalImages = 5;
$all = range(1,$totalImages);
shuffle($all);
foreach ($all as $single) {
echo "<li><a href='' /><img src='"; echo bloginfo('template_url') . "/images/ads/ad_0$single.png' alt='ad' /></li>";
}
?>
</ul>
The simplest way is to have an array of images with links and then have $single be the array index. There are two ways to accomplish this. One is to have a two dimensionsal array that contains both links and images, the other is to have two parallel arrays. Here are both options illustrated:
<?php
// one two dimensional array
$ads = array( array("1.png", "/page1"), array("2.png", "/page2"), array("3.png", "/page3"), array("4.png", "/page4"), array("super-special-buy-now.png", "/billy-mays-lives") );
// or two one dimensions arrays
$ads_images = array("1.png", "2.png", "3.png", "4.png", "super-special-buy-now.png");
$ads_links = array("/page1", "/page2", "/page3", "/page4", "/billy-mays-lives");
// now your code
$totalImages = 5;
$all = range(1,$totalImages);
shuffle($all);
$html = "";
foreach ($all as $single) {
// option 1, two dimensional array
$html += sprintf('<li><a href="%s"><img src="%s/images/ads/ad_0%s" alt="ad" /></li>',
$ads[$single][1], bloginfo('template_url'), $ads[$single][0]);
// option 2, two parallel arrays
$html += sprintf('<li><a href="%s"><img src="%s/images/ads/ad_0%s" alt="ad" /></li>',
$ads_links[$single], bloginfo('template_url'), $ads_images[$single]);
}
echo $html;
?>
Normally you would either:
- Shuffle them already in query which retrieves them from a database, or
- Shuffle an array of id/url pairs:
$d => array (
array('id'=>1,'url'=>'...'),
array('id'=>2,'url'=>'...')
array('id'=>3,'url'=>'...'));
array_shuffle($d);
Which would also make it easier to drop add 1 instead over overwriting it (with all server / browsercaching problems that could come from it).

Categories