foreach php statement - php

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.

Related

Sort a flat array in recurring ascending sequences

I am trying to sort it in a repeating, sequential pattern of numerical order with the largest sets first.
Sample array:
$array = [1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3];
In the above array, I have the highest value of 5 which appears twice so the first two sets would 1,2,3,4,5 then it would revert to the second, highest value set etc.
Desired result:
[1,2,3,4,5,1,2,3,4,5,1,2,3,4,1,2,4]
I am pretty sure I can split the array into chunks of the integer values then cherrypick an item from each subarray sequentially until there are no remaining items, but I just feel that this is going to be poor for performance and I don't want to miss a simple trick that PHP can already handle.
Here's my attempt at a very manual loop using process, the idea is to simply sort the numbers into containers for array_unshifting. I'm sure this is terrible and I'd love someone to do this in five lines or less :)
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
// Build the container array
$numbers = array_fill_keys(array_unique($array),array());
// Assignment
foreach( $array as $number )
{
$numbers[ $number ][] = $number;
}
// Worker Loop
$output = array();
while( empty( $numbers ) === false )
{
foreach( $numbers as $outer => $inner )
{
$output[] = array_shift( $numbers[ $outer ] );
if( empty( $numbers[ $outer ] ) )
{
unset( $numbers[ $outer ] );
}
}
}
var_dump( $output );
I think I'd look at this not as a sorting problem, but alternating values from multiple lists, so rather than coming up with sets of distinct numbers I'd make sets of the same number.
Since there's no difference between one 1 and another, all you actually need is to count the number of times each appears. It turns out PHP can do this for you with aaray_count_values.
$sets = array_count_values ($input);
Then we can make sure the sets are in order by sorting by key:
ksort($sets);
Now, we iterate round our sets, counting down how many times we've output each number. Once we've "drained" a set, we remove it from the list, and once we have no sets left, we're all done:
$output = [];
while ( count($sets) > 0 ) {
foreach ( $sets as $number => $count ) {
$output[] = $number;
if ( --$sets[$number] == 0 ) {
unset($sets[$number]);
}
}
}
This algorithm could be adapted for cases where the values are actually distinct but can be put into sets, by having the value of each set be a list rather than a count. Instead of -- you'd use array_shift, and then check if the length of the set was zero.
You can use only linear logic to sort using php functions. Here is optimized way to fill data structures. It can be used for streams, generators or anything else you can iterate and compare.
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
$chunks = [];
$index = [];
foreach($array as $i){
if(!isset($index[$i])){
$index[$i]=0;
}
if(!isset($chunks[$index[$i]])){
$chunks[$index[$i]]=[$i];
} else {
$chunks[$index[$i]][] = $i;
}
$index[$i]++;
}
$result = call_user_func_array('array_merge', $chunks);
print_r($result);
<?php
$array = array(1,1,1,2,3,2,3,4,5,4,4,4,5,1,2,2,3);
sort($array);
while($array) {
$n = 0;
foreach($array as $k => $v) {
if($v>$n) {
$result[] = $n = $v;
unset($array[$k]);
}
}
}
echo implode(',', $result);
Output:
1,2,3,4,5,1,2,3,4,5,1,2,3,4,1,2,4
New, more elegant, more performant, more concise answer:
Create a sorting array where each number gets its own independent counter to increment. Then use array_multisort() to sort by this grouping array, then sort by values ascending.
Code: (Demo)
$encounters = [];
foreach ($array as $v) {
$encounters[] = $e[$v] = ($e[$v] ?? 0) + 1;
}
array_multisort($encounters, $array);
var_export($array);
Or with a functional style with no global variable declarations: (Demo)
array_multisort(
array_map(
function($v) {
static $e;
return $e[$v] = ($e[$v] ?? 0) + 1;
},
$array
),
$array
);
var_export($array);
Old answer:
My advice is functionally identical to #El''s snippet, but is implemented in a more concise/modern/attractive fashion.
After ensuring that the input array is sorted, make only one pass over the array and push each re-encountered value into its next row of values. The $counter variable indicates which row (in $grouped) the current value should be pushed into. When finished looping and grouping, $grouped will have unique values in each row. The final step is to merge/flatten the rows (preserving their order).
Code: (Demo)
$grouped = [];
$counter = [];
sort($array);
foreach ($array as $v) {
$counter[$v] = ($counter[$v] ?? -1) + 1;
$grouped[$counter[$v]][] = $v;
}
var_export(array_merge(...$grouped));

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]
}

compare two arrays in PHP and get the difference in key

I have been reading through the manual to find a function that does what I want but I ended up doing it myself. I want to compare two arrays and calculate the difference between the keys. Or more practically analyse the difference in order of the values.
I have done this as follows, but I have a feeling this can be done better.
if anyone has an idea how to improve this please let me know becasue im eager to improve.
<?php
$goodarray = array(300,250,200,150,100);
$usersupliedarray = array(250,300,200,150,100); // first two spots are wrong
$score = count($goodarray);
foreach($usersupliedarray as $key => $value){
$arraykey = array_search($value, $goodarray);
$difference = abs($key-$arraykey);
$score = $score + $difference;
echo "$value $goodarray[$key] ($difference = $score) <hr />";
}
array_map with a void callback can come in handy here, for example,
$a = array(300,250,200,150,100);
$b = array(250,300,200,150,100);
$faults = 0;
foreach(array_map(null, $a, $b) as $x)
$faults += $x[0] != $x[1]; // x[0] is $a element, x[1] is $b
print $faults; // 2
UPD: if you want to compute distances between equal elements, and not just count differences, your original code looks just fine to me. One improvement which can be made is to get rid of inefficient array_search and to use an "inverted index" of the first array instead:
foreach($a as $pos => $val)
$inv[$val] = $pos;
or just
$inv = array_flip($a);
and then
foreach($b as $pos => $val)
$score += abs($pos - $inv[$val]);

equivalent syntax for 'for loop' & 'while loop'?

I know basic examples about foreach to for loop and while loop since I was begin coding I didn't paying attention from the speed of executing a script which it is very very important since then I keep converting all my for each statement to for loop. If it's comes to array i'm quite confused -_-. I know it gives me down vote posting this. LIKE I'd rather let people figure things out for myself.
I just need a bit of guide using a for loop statement. How can I convert the following foreach loop to for loop/ while loop statement?
like what I seen on phpbenchmark.com as
$i = 0; while($i < 1000000) ++$i;
for($i = 0; $i < 1000000; ++$i);
CODE:
<?php
$user['001'] = 'A';
$user['002'] = 'B';
$user['003'] = 'C';
$user['004'] = 'D';
foreach($user as $id => $name)
{
echo '<br>Id='.$id.'Name='.$name;
}
?>
thanks alot.
EXPECTED OUTPUT LIKE foreach output:
Id=001Name=A
Id=002Name=B
Id=003Name=C
Id=004Name=D
also what if I have an array keys like
$user['AAA'] = 'A';
$user['BBB'] = 'B';
$user['CCC'] = 'C';
$user['DDD'] = 'D';
it will output as:
Id=AAAName=A
Id=AAAName=B
Id=AAAName=C
Id=AAAName=D
The for and while loops you show are simply incrementing a number, which you can use to access elements of an array if the keys of that array are equivalent to those numbers. In other words, for or while loops have nothing to do with arrays as such, you're just using a number as a key to an array.
If your array keys are not simple continuous integers, this is more problematic. You could try to construct the correct keys from your $i variable, but why? You should just iterate explicitly over the keys of the array, for which foreach is perfect. You can also do it with each or any number of other complicated ways:
while (list($key, $value) = each($array)) {
...
}
But I doubt it's going to be significantly faster than a foreach.
Something like this...
<?php
$user['001'] = 'A';
$user['002'] = 'B';
$user['003'] = 'C';
$user['004'] = 'D';
while (current($user)) {
echo '<br>Id='.key($user).'Name='.$user[key($user)];
next($user);
}
try this
$user['001'] = 'A';
$user['002'] = 'B';
$user['003'] = 'C';
$user['004'] = 'D';
$keys = array_keys($user);
$length = sizeof($user);
for($i=0; $i<$length; $i++) {
echo 'id: '.$keys[$i].' value: '.$user[$keys[$i]].'<br />';
}
do you wanted something like this?
$length = count($user);
for ($i = 0; $i < $length; $i++) {
print $user[$i];
}
EDIT: or something like this?
$user = array ( '001' => 'A',
'002' => 'B',
'033' => 'C' );
while( list ( $id, $name) = each ( $user) )
{
echo '<br>Id=' .$id. 'Name='.$name;
}
EDIT:also works with you r AAA = A etc case

PHP : How to get sum of multidimensionnal arrays with specific keys?

I would like to know how to get the sum of some key values of multi-dimensional arrays, knowing that some keys are variables; here is an example of the situation :
The array could be written like this :
$array[$dim1][$dim2][$dim3][$dim4] = $variable_value;
$dim1, 2, 3 and 4 are arrays with dimensions, and we don't know the name of the $dim1, 2, 3 and 4.
We want the sum of all $variable_value of each dimensions, but we can't do array_sum($array[$dim1][$dim2][$dim3][$dim4]) because the $dim are not known.
The algorithm I need to find must permit me to apply filters on the sums, like "get the sum of all the $variable_value where $dim3 = $variableX...", so a function like this :
function array_sum_filter($array, $dimension, [$filter_on_key_value])
Any ideas?
use for/foreach loops for looping through the multidimensional array and an if statement to check if $dim3 = $variableX...
You can try this using RecursiveArrayIterator and RecursiveIteratorIterator
$sum = 0;
$specific = 0;
$array = array();
$array["A"]["B"]["C"]["D"] = 5;
$array["A"]["B"]["K"]["D"] = 3;
$array["A"]["C"] = 2;
$array_obj = new RecursiveIteratorIterator(new RecursiveArrayIterator($array));
foreach ( $array_obj as $key => $value ) {
$sum += $value;
if ($key == "D")
$specific += $value;
}
echo $sum, PHP_EOL;
echo $specific, PHP_EOL;
Output
10
8

Categories