Reverse order of foreach list items - php

I would like to reverse the order of this code's list items. Basically it's a set of years going from oldest to recent and I am trying to reverse that output.
<?php
$j=1;
foreach ( $skills_nav as $skill ) {
$a = '<li><a href="#" data-filter=".'.$skill->slug.'">';
$a .= $skill->name;
$a .= '</a></li>';
echo $a;
echo "\n";
$j++;
}
?>

Walking Backwards
If you're looking for a purely PHP solution, you can also simply count backwards through the list, access it front-to-back:
$accounts = Array(
'#jonathansampson',
'#f12devtools',
'#ieanswers'
);
$index = count($accounts);
while($index) {
echo sprintf("<li>%s</li>", $accounts[--$index]);
}
The above sets $index to the total number of elements, and then begins accessing them back-to-front, reducing the index value for the next iteration.
Reversing the Array
You could also leverage the array_reverse function to invert the values of your array, allowing you to access them in reverse order:
$accounts = Array(
'#jonathansampson',
'#f12devtools',
'#ieanswers'
);
foreach ( array_reverse($accounts) as $account ) {
echo sprintf("<li>%s</li>", $account);
}

Or you could use the array_reverse function.

array_reverse() does not alter the source array, but returns a new array. (See array_reverse().) So you either need to store the new array first or just use function within the declaration of your for loop.
<?php
$input = array('a', 'b', 'c');
foreach (array_reverse($input) as $value) {
echo $value."\n";
}
?>
The output will be:
c
b
a
So, to address to OP, the code becomes:
<?php
$j=1;
foreach ( array_reverse($skills_nav) as $skill ) {
$a = '<li><a href="#" data-filter=".'.$skill->slug.'">';
$a .= $skill->name;
$a .= '</a></li>';
echo $a;
echo "\n";
$j++;
}
Lastly, I'm going to guess that the $j was either a counter used in an initial attempt to get a reverse walk of $skills_nav, or a way to count the $skills_nav array. If the former, it should be removed now that you have the correct solution. If the latter, it can be replaced, outside of the loop, with a $j = count($skills_nav).

If you don't mind destroying the array (or a temp copy of it) you can do:
$stack = array("orange", "banana", "apple", "raspberry");
while ($fruit = array_pop($stack)){
echo $fruit . "\n<br>";
}
produces:
raspberry
apple
banana
orange
I think this solution reads cleaner than fiddling with an index and you are less likely to introduce index handling mistakes, but the problem with it is that your code will likely take slightly longer to run if you have to create a temporary copy of the array first.
Fiddling with an index is likely to run faster, and it may also come in handy if you actually need to reference the index, as in:
$stack = array("orange", "banana", "apple", "raspberry");
$index = count($stack) - 1;
while($index > -1){
echo $stack[$index] ." is in position ". $index . "\n<br>";
$index--;
}
But as you can see, you have to be very careful with the index...

You can use usort function to create own sorting rules

Assuming you just need to reverse an indexed array (not associative or multidimensional) a simple for loop would suffice:
$fruits = ['bananas', 'apples', 'pears'];
for($i = count($fruits)-1; $i >= 0; $i--) {
echo $fruits[$i] . '<br>';
}

If your array is populated through an SQL Query consider reversing the result in MySQL, ie :
SELECT * FROM model_input order by creation_date desc

If you do not have Boolean false values in your array, you could use next code based on internal pointer functions:
$array = ['banana', 'apple', 'pineapple', 'lemon'];
$value = end($array);
while ($value !== false) {
// In case you need a key
$key = key($array);
// Do something you need to
echo $key . ' => ' . $value . "\n";
// Move pointer
$value = prev($array);
}
This solution works for associative arrays with arbitrary keys and do not require altering existing or creating a new one.

<?php
$j=1;
array_reverse($skills_nav);
foreach ( $skills_nav as $skill ) {
$a = '<li><a href="#" data-filter=".'.$skill->slug.'">';
$a .= $skill->name;
$a .= '</a></li>';
echo $a;
echo "\n";
$j++;
}
?>

Related

Finding the first, last and nth row in a foreach loop

I was wondering if PHP has a gracefull method to find the first, last and/or nth row in a foreach loop.
I could do it using a counter as follows:
$i = 0;
$last = count($array)-1;
foreach ($array as $key => $row) {
if ($i == 0) {
// First row
}
if ($i == $last) {
// Last row
}
$i++;
}
But somehow this feels like a bit of a dirty fix. Any solutions or suggestions?
Edit
As suggested in the comments I moved the count($array) outside the loop.
foreach ($array as $key => $row) {
$index = array_search($key, array_keys($array));
if ($index == 0) {
// First row
}
if ($index == count($array) - 1) {
// Last row
}
}
In php we have current and end function to get first and last value of array.
<?php
$transport = array('foot', 'bike', 'car', 'plane');
echo $first = current($transport); // 'foot';
echo $end = end($transport); // 'plane';
?>
Modified :
Easy way without using current or end or foreach loop:
$last = count($transport) - 1;
echo "First : $transport[0]";
echo "</br>";
echo "Last : $transport[$last]";
Using Arrays
For the first element in an array you can simply seek $array[0];. Depending on the array cursor you can also use current($array);
For the middle of an array you can use a combination of array_search() and array_keys().
For the end of an array you can use end($array); noting that this aslso moves the array cursor to the last element as well (as opposed to simply returning the value).
Using Iterators
However ArrayIterator's may also work well in your case:
The first element is available at ArrayIterator::current(); once constructed. (If you're halfway through the iterator you'll need to reset().)
For the n'th or a middle element you can use an undocumented Iterator::seek($index); method.
For the last element you can use a combination of seek() and count().
For example:
$array = array('frank' => 'one',
'susan' => 'two',
'ahmed' => 'three');
$arrayobject = new ArrayObject($array);
$iterator = $arrayobject->getIterator();
// First:
echo $iterator->current() . PHP_EOL;
// n'th: (taken from the documentation)
if($iterator->valid()){
$iterator->seek(1); // expected: two, output: two
echo $iterator->current() . PHP_EOL; // two
}
// last:
$iterator->seek(count($iterator)-1);
echo $iterator->current() . PHP_EOL;
$arr = ["A", "B", "C", "D", "E"];
reset($arr);
// Get First Value From Array
echo current($arr);
// Get Last Value From Array
echo end($arr);
Visit below link for details of above used functions.
reset() : http://php.net/manual/en/function.reset.php
current() : http://php.net/manual/en/function.current.php
end() : http://php.net/manual/en/function.end.php

Passing two variables into a 'foreach' loop

I need help regarding a foreach() loop. aCan I pass two variables into one foreach loop?
For example,
foreach($specs as $name, $material as $mat)
{
echo $name;
echo $mat;
}
Here, $specs and $material are nothing but an array in which I am storing some specification and material name and want to print them one by one. I am getting the following error after running:
Parse error: syntax error, unexpected ',', expecting ')' on foreach line.
In the Beginning, was the For Loop:
$n = sizeof($name);
for ($i=0; i < $n; $i++) {
echo $name[$i];
echo $mat[$i];
}
You can not have two arrays in a foreach loop like that, but you can use array_combine to combine an array and later just print it out:
$arraye = array_combine($name, $material);
foreach ($arraye as $k=> $a) {
echo $k. ' '. $a ;
}
Output:
first 112
second 332
But if any of the names don't have material then you must have an empty/null value in it, otherwise there is no way that you can sure which material belongs to which name. So I think you should have an array like:
$name = array('amy','john','morris','rahul');
$material = array('1w','4fr',null,'ff');
Now you can just
if (count($name) == count($material)) {
for ($i=0; $i < $count($name); $i++) {
echo $name[$i];
echo $material[$i];
}
Just FYI: If you want to have multiple arrays in foreach, you can use list:
foreach ($array as list($arr1, $arr2)) {...}
Though first you need to do this: $array = array($specs,$material)
<?php
$abc = array('first','second');
$add = array('112','332');
$array = array($abc,$add);
foreach ($array as list($arr1, $arr2)) {
echo $arr1;
echo $arr2;
}
The output will be:
first
second
112
332
And still I don't think it will serve your exact purpose, because it goes through the first array and then the second array.
You can use the MultipleIterator of SPL. It's a bit verbose for this simple use case, but works well with all edge cases:
$iterator = new MultipleIterator();
$iterator->attachIterator(new ArrayIterator($specs));
$iterator->attachIterator(new ArrayIterator($material));
foreach ($iterator as $current) {
$name = $current[0];
$mat = $current[1];
}
The default settings of the iterator are that it stops as soon as one of the arrays has no more elements and that you can access the current elements with a numeric key, in the order that the iterators have been attached ($current[0] and $current[1]).
Examples for the different settings can be found in the constructor documentation.
This is one of the ways to do this:
foreach ($specs as $k => $name) {
assert(isset($material[$k]));
$mat = $material[$k];
}
If you have ['foo', 'bar'] and [2 => 'mat1', 3 => 'mat2'] then this approach won't work but you can use array_values to discard keys first.
Another apprach would be (which is very close to what you wanted, in fact):
while ((list($name) = each($specs)) && (list($mat) = each($material))) {
}
This will terminate when one of them ends and will work if they are not indexed the same. However, if they are supposed to be indexed the same then perhaps the solution above is better. Hard to say in general.
Do it using a for loop...
Check it below:
<?php
$specs = array('a', 'b', 'c', 'd');
$material = array('x', 'y', 'z');
$count = count($specs) > count($material) ? count($specs) : count($material);
for ($i=0;$i<$count;$i++ )
{
if (isset($specs[$i]))
echo $specs[$i];
if (isset($material[$i]))
echo $material[$i];
}
?>
OUTPUT
axbyczd
Simply use a for loop. And inside that loop, extract values of your array:
For (I=0 to 100) {
Echo array1[i];
Echo array2[i]
}

echo a number in php

I am trying to learn php, and I am playing around with while loops. I was wondering how to print out a specific number in an array in php. Fx:
$a = [1,3,5,7,9,11,13];
$s = 3;
while($a == 3) {
echo $s.' is in the row';
$a++;
}
In this example I would like to run through the $a and see if 3 exist there. If it does it has to echo '3 is in the row' I tried to make a while loop, but it is not correct. Can anyone see what I am doing wrong? Just to say it, I think it is very wrong, but I don't know how to solve it, if I have to use the while loop?
Best Regards
Mads
Your while condition reads: "While the value of $a equals 3", but $a is an array, so its value can't ever be 3. The loop will never be executed. In PHP, we would write:
if (in_array($s, $a))
echo $s, ' was found in the array';
Or, if you insist on writing loops:
foreach ($a as $key => $value)
{
if ($value == $s)
{
echo $s, ' was found at offset ', $key;
break;//end terminate loop
}
}
Of course, you could also write:
for ($i=0, $j=count($a);$i<$j;++$j)
{
if ($a[$i] == $s)
{//you could move this condition to the loop itself, even
echo $s, ' found in array at offset ', $i;
break;
}
}
You can, if you want use a while loop, too, but that wouldn't be the best choice for your particular case. Just read through the manual on php.net. There are many, many array_* functions available, and there are many ways to iterate over your data.
Another worry is your using the array name as a sort-of C-style pointer: $a++; in C, an pointer can be incremented to set it to point to the next value in an array (if the new memory address is valid, and the pointer is valid, and all of the other things you have to worry about in C). PHP does not work this way. An array isn't really an array: it's a hash map. incrementing an array, therefore, is pointless and most likely to be a bug. The for loop is the closest you can get to traversing an array using the ++ operator.
You're looking for in_array. This checks if a value exists in an array, in the form of:
in_array ( mixed $needle , array $haystack )
So, in your case, you'd want to do:
$a = [1,3,5,7,9,11,13];
$s = 3;
if (in_array($s, $a)) {
echo $s.' is in the row';
}
foreach($a as $b) {
if($b == 3)
echo $b.' is in the row';
}
Modify slightly your code changing while condition:
$a = array(1,3,5,7,9,11,13);
$s = 3;
$counter = 0;
while($counter < count($a)) {
if ( $a[$counter] == $s )
echo $s.' is in the row';
$counter++;
}
Added counter to iterate through while loop until end of array.
count() method returns number of items in array.
This solution prints all occurences of your number.
To have better code, change names of variables:
$numbers = array(1,3,5,7,9,11,13);
$target = 3;
$counter = 0;
while($counter < count($numbers)) {
if ( $numbers[$counter] == $target )
echo $target.' is in the row';
$counter++;
}
There are two ways to do it,
First, you can loop through all items in the array using a foreach() loop.
That way, you can go through them all and if you have multiple conditions, it makes your code a bit more readable.
And example of that loop is like this:
foreach($array as $array_item) {
if($array_item === 3) {
echo "3 is in the array";
}
}
The alternative is to use a built in function to find if something is in the array. THis is probably much faster, though I haven't benchmarked the difference.
if(in_array(3, $array)) {
echo "3 is in the array";
}
you can use
array_search ,in_array , and forearch or for loops to itertate through the array.
For learning purposes
$a = [1,3,5,7,9,11,13];
$s = 3;
for($i=0;$i<count($a);$i++)
{
if($a[$i]==$s){
echo $s.' is in the row';
}
}
of course in real life
if (in_array(3, $a)) {
// Do something
}
would be better;
<?php
$a = [1,3,5,7,9,11,13];
$s = 3;
for($a=0;$a < 20; $a++)
{
while($a == 3) {
echo $s.' is in the row';
//$a++;
}
}
?>

PHP Count values of an array

Is there a way to count the values of a multidimensional array()?
$families = array
(
"Test"=>array
(
"test1",
"test2",
"test3"
)
);
So for instance, I'd want to count the 3 values within the array "Test"... ('test1', 'test2', 'test3')?
$families = array
(
"Test"=>array
(
"test1",
"test2",
"test3"
)
);
echo count($families["Test"]);
I think I've just come up with a rather different way of counting the elements of an (unlimited) MD array.
<?php
$array = array("ab", "cd", array("ef", "gh", array("ij")), "kl");
$i = 0;
array_walk_recursive($array, function() { global $i; return ++$i; });
echo $i;
?>
Perhaps not the most economical way of doing the count, but it seems to work! You could, inside the anonymous function, only add the element to the counted total if it had a non empty value, for example, if you wanted to extend the functionality. An example of something similar could be seen here:
<?php
$array = array("ab", "cd", array("ef", "gh", array("ij")), "kl");
$i = 0;
array_walk_recursive($array, function($value, $key) { global $i; if ($value == 'gh') ++$i; });
echo $i;
?>
The count method must get you there. Depending on what your actual problem is you maybe need to write some (recursive) loop to sum all items.
A static array:
echo 'Test has ' . count($families['test']) . ' family members';
If you don't know how long your array is going to be:
foreach($families as $familyName => $familyMembers)
{
echo $familyName . ' has got ' . count($familyMembers) . ' family members.';
}
function countArrayValues($ar, $count_arrays = false) {
$cnt = 0;
foreach ($ar as $key => $val) {
if (is_array($ar[$key])) {
if ($count_arrays)
$cnt++;
$cnt += countArrayValues($ar);
}
else
$cnt++;
}
return $cnt;
}
this is custom function written by me, just pass an array and you will get full count of values. This method wont count elements which are arrays if you pass second parameter as false, or you don't pass anything. Pass tru if you want to count them also.
$count = countArrayValues($your_array);

foreach php statement

I need to combine two foreach statement into one for example
foreach ($categories_stack as $category)
foreach ($page_name as $value)
I need to add these into the same foreach statement
Is this possible if so how?
(I am not sure I have understood your question completely. I am assuming that you want to iterate through the two lists in parallel)
You can do it using for loop as follows :
$n = min(count($category), count($value));
for($c = 0; $c < $n; $c = $c + 1){
$categories_stack = $category[$c];
$pagename = $value[$c];
...
}
To achieve the same with foreach you need a function similar to Python's zip() function.
In Python, it would be :
for categories_stack, pagename in zip(categories, values):
print categories_stack, pagename
Since PHP doesn't have a standard zip() function, you'll have to write such a function on your own or go with the for loop solution.
You can do nested foreachs if that's what you want. But without knowing more of your data, it's impossible to say if this helps:
foreach ($categories_stack as $category) {
foreach ($page_name as $value) {
}
}
Probably you want to print out all pages in a category? That probably won't work, so can you give a bit more info on how the arrays look like and relate to each other?
This loop will continue to the length of the longest array and return null for where there are no matching elements in either of the arrays. Try it out!
$a = array(1 => "a",25 => "b", 10 => "c",99=>"d");
$b = array(15=>1,5=>2,6=>3);
$ao = new ArrayObject($a);
$bo = new ArrayObject($b);
$ai = $ao->getIterator();
$bi = $bo->getIterator();
for (
$ai->rewind(),$bi->rewind(),$av = $ai->current(),$bv = $bi->current();
list($av,$bv) =
array(
($ai->valid() ? $ai->current() : null),
($bi->valid() ? $bi->current() : null)
),
($ai->valid() || $bi->valid());
($ai->valid() ? $ai->next() : null),($bi->valid() ? $bi->next() : null))
{
echo "\$av = $av\n";
echo "\$bv = $bv\n";
}
I cannot really tell from the question exactly how you want to traverse the two arrays. For a nested foreach you simply write
foreach ($myArray as $k => $v) {
foreach ($mySecondArray as $kb => $vb {
}
}
However you can do all sorts of things with some creative use of callback functions. In this case an anonymous function returning two items from each array on each iteration. It's then easy to use the iteration value as an array or split it into variables using list() as done below.
This also has the added benefit of working regardless of key structure. I's purely based on the ordering of array elements. Just use the appropriate sorting function if the elements are out of order.
It does not worry about the length of the arrays as there is no error reported, so make sure you keep an eye out for empty values.
$a = array("a","b","c");
$b = array(1,2,3);
foreach (
array_map(
create_function(
'$a,$b', 'return array($a,$b);'
)
,$a,$b
)
as $value
)
{
list($a,$b) = $value;
echo "\$a = $a\n";
echo "\$b = $b\n";
}
Output
$a = a
$b = 1
$a = b
$b = 2
$a = c
$b = 3
Here's another one for you that stops on either of the lists ending. Same as using min(count(a),count(b). Useful if you have arrays of same length. If someone can make it continue to the max(count(a),count(b)) let me know.
$ao = new ArrayObject($a);
$bo = new ArrayObject($b);
$ai = $ao->getIterator();
$bi = $bo->getIterator();
for (
$ai->rewind(),$bi->rewind();
$av = $ai->current(),$bv=$bi->current();
$ai->next(),$bi->next())
{
echo "\$av = $av\n";
echo "\$bv = $bv\n";
}
This is where the venerable for loop comes in handy:
for(
$i = 0,
$n = sizeof($categories_stack),
$m = sizeof($page_name);
$i < $n && $i < $m;
$i++
) {
$category = $categories_stack[$i];
$value = $page_name[$i];
// do stuff here ....
}
Surely you can just merge the arrays before looping?
$data = array_merge($categories_stack, $page_name);
foreach($data AS $item){
...
}
Do the array elements have a direct correspondence with one another, i.e. is there an element in $page_name for each element in $categories_stack? If so, just iterate over the keys and values (assuming they have the same keys):
foreach ($categories_stack as $key => $value)
{
$category = $value;
$page = $page_name[$key];
// ...
}
Could you just nest them with variables outside the scope of the foreach, or prehaps store the content as an array similar to a KVP setup? My answer is vague but I'm not really sure why you're trying to accomplish this.

Categories