How can PHP's foreach() be successfully nested on a single array? - php-internals

Consider the following code:
$a = [1, 2, 3];
foreach ($a as $x) {
foreach ($a as $y) {
echo "$x $y\n";
}
}
As one would expect, it gives the following result:
1 1
1 2
1 3
2 1
2 2
2 3
3 1
3 2
3 3
Although happy with the result, I'm surprised it works, because according to the manual, it relies on the array's internal pointer:
When foreach first starts executing, the internal array pointer is automatically reset to the first element of the array. This means that you do not need to call reset() before a foreach loop.
As foreach relies on the internal array pointer, changing it within the loop may lead to unexpected behavior.
So we could expect that using a nested foreach inside the first one, would share the same internal pointer, and produce the following result:
1 1
1 2
1 3
Because the first foreach would see the state of the internal pointer left by the nested foreach.
I can think of two possible explanations to the actual behaviour:
The PHP manual is wrong / outdated, and PHP uses a separate pointer specific to every foreach;
The nested foreach internally triggers a duplication of the array in memory, so they would each have their own pointer.
Just for my culture, how does this work internally?

Short answer. PHP indeed copies the array (that is, the array structure) in this situation. Foreach can do that in various scenarios to prevent problems like this. Some people believe that foreach always copies the array, but that is not the case (that would be inefficient).
I found a great blog post that describes this behavior in more detail:
PHP internals: When does foreach copy?
The summary:
foreach will copy the array structure if and only if the iterated
array is not referenced and has a refcount > 1
foreach will
additionally copy the array values if and only if the previous point
applies and the iteration is done by reference

Related

Unexpected Hash flattening

I'm looking for explanation why those two data structures are not equal:
$ perl6 -e 'use Test; is-deeply [ { a => "b" } ], [ { a => "b" }, ];'
not ok 1 -
# Failed test at -e line 1
# expected: $[{:a("b")},]
# got: $[:a("b")]
Trailing comma in Hashes and Arrays is meaningless just like in P5:
$ perl6 -e '[ 1 ].elems.say; [ 1, ].elems.say'
1
1
But without it Hash is somehow lost and it gets flattened to array of Pairs:
$ perl6 -e '[ { a => "b", c => "d" } ].elems.say;'
2
I suspect some Great List Refactor laws apply here but I'd like to get more detailed explanation to understand logic behind this flattening.
Trailing comma in Hashes and Arrays is meaningless just like in P5
No, it's not meaningless:
(1 ).WHAT.say ; # (Int)
(1,).WHAT.say ; # (List)
The big simplification in the Great List Refactor was switching to the single argument rule for iterating features1. That is to say, features like a for or the array and hash composers (and subscripts) always get a single argument. That is indeed what's going on with your original example.
The single argument may be -- often will be -- a list of values, possibly even a list of lists etc., but the top level list would still then be a single argument to the iterating feature.
If the single argument to an iterating feature does the Iterable role (for example lists, arrays, and hashes), then it's iterated. (This is an imprecise formulation; see my answer to "When does for call the iterator method?" for a more precise one.)
So the key thing to note here about that extra comma is that if the single argument does not do the Iterable role, such as 1, then the end result is exactly the same as if the argument were instead a list containing just that one value (i.e. 1,):
.perl.say for {:a("b")} ; # :a("b") Iterable Hash was iterated
.perl.say for {:a("b")} , ; # {:a("b")} Iterable List was iterated
.perl.say for 1 ; # 1 Non Iterable 1 left as is
.perl.say for 1 , ; # 1 Iterable List was iterated
The typical way "to preserve structure [other than] using trailing comma when single element list is declared" (see comment below), i.e. to
stop a single Iterable value being iterated as it normally would, is by item-izing it with a $:
my #t = [ $[ $[ "a" ] ] ];
#t.push: "b";
#t.perl.say; # [[["a"],], "b"]
1 The iteration is used to get values to be passed to some code in the case of a for; to get values to become elements of the array/hash being constructed in the case of a composer; to get an indexing slice in the case of a subscript; and so on for other iterating features.

How to assign values to a string? [duplicate]

This question already has answers here:
Create variables with names from strings
(6 answers)
Closed 6 years ago.
I have a loop running on multiple workstations, each loop is dealing with 5 different classes, when the results is acquired it is to save the result with the name of the classes it used.
For example on workstation 1 I am using:
class1 = 1;
class2 = 10;
%code that will run on all images associated with classes 1:10
% final_result from all 10 classes is calculated here
I want to save this now, with the name such as:
result_1_10 = final_result;
save result_1_10 result_1_10;
I can do this manually but its becoming very difficult to change the values on all machines after one value is changed, I would rather it save these and pick up the numbers from the two variables class1 and class2.
Here is what I tried:
['result_' num2str(class1) '_' num2str(class2)];
This would give me result_1_10. Which is what I wanted but it is a string, rather than a variable, so I cannot assign the result value to it
['result_' num2str(class1) '_' num2str(class2)] = final_result;
Would give the error:
Error: An array for multiple LHS assignment cannot contain
LEX_TS_STRING.
I even tried str2num(num2str(class1)) but that would also give an error.
How do I actually do this?
Thank you
While you can do this, it is very much discouraged by The Mathworks themselves. Any time you are trying to store information about what a variable contains within the variable name itself, that's a sign that maybe things should be rearranged a bit. Maybe consider using a different data structure.
Consider for example using a struct where you keep the classes as fields and the result as a field.
S.class1 = 1;
S.class2 = 10;
S.result = final_result;
You could then even create an array of structs holding your data.
S = struct('class1', {1, 2, 1}, ...
'class2', {10, 11, 10}, ...
'result', {rand(10), rand(10), rand(10)});
Then you could grab all results when class1 was 1:
S([S.class1 == 1]);
Or all results when class1 as 1 and class2 was 10
S([S.class1 == 1] & [S.class2 == 10]);
If you insist on doing it the way that you've laid out, you'll have to use eval or assignin to do that. Also, sprintf is often more concise than string concatenations.
variable = sprintf('result_%d_%d', class1, class2);
eval([variable, '= final_result;']);

moving objects in NSMutableArray without changing array size

I have a 'MutableArray' that I want to edit by moving different objects in it up and down the index via the method shown here: NSMutablearray move object from index to index.
My problem is that Xcode first takes care of the 'removeObjectAtIndex' method before the 'insertObject:atIndex:' so the array actually shrinks in size which makes certain transitions impossible. An example would be if my 'array' has 3 members and I change the third member's index from 2 to 2 so nothing should happen but actually the app crashes because after the removal the index bound is now [0,1].
Below is the code I am using to implement the move in array, I also get a Parse Issue: Expected identifier error from the compiler at the 'if' statement right behind the queue.count. Any help on both would be much appreciated.
-(void)makeRankChange:(NSMutableArray *)queue{
for (int queueCount =0; queueCount<queue.count; queueCount++) {
QueueMember *member = [queue objectAtIndex:queueCount];
if (member.rank != queueCount+1) {
if ([0<member.rank] && [member.rank < [queue.count(expected identifier here:Im not sure why)]]) {
[queue insertObject:member atIndex:member.rank-1];
[queue removeObjectAtIndex:queueCount];
}
}
}
}
How about replacing the value at the index:
[queue replaceObjectAtIndex:queueCount withObject:member];
The error is most likely from the '[' brackets in the if statement

string 'w32' == 0 evaluates to true in php. huh?

So I was getting a notice in my php while creating a google product feed.
The notice was
"The following php notice has occurred 4989 times on the _ site today:
PHP Notice: Undefined index: 0 in /xxx/Status.php on line 583"
This was the code in that class
public function inStockLocally($productcode)
{
if($this->_status[$productcode]['status'] == self::IN_STOCK) {
return $this->_status[$productcode]['in_stock_local'];
}
return false;
}
The function was getting a $productcode = 0, but the productcode was infact 'w32', so the key didn't exist.
up the stack where the function was being called I put this in, in order to break on the troublesome product.
if ($productcode == 0) {
$test = 'breakhere';
}
Using netbeans and firebug, it broke on the line when $productcode = 'w32'
So my question is why does 'w32' == 0 evaluate to true?
It is also evaluating to true with other similar structure codes like 'h94'.
Any help would be appreciated as no one in the department can figure out why this is happening.
I guess I didn't put enough info in the q. Two things going on.
1. 'w32' converted to a number = 0 for some reason. 2. [0] is being inserted as my key in the array when the productcode has the structure 'x##';
I'm a little new here, so pardon if this isn't the answer you were expecting, but PHP does a lot of automatic type conversion. So any string that doesn't start with a numeric character (0..9, +, -, etc) will evaluate to zero.
"If you compare a number with a string or the comparison involves numerical strings, then each string is converted to a number and the comparison performed numerically. "
http://php.net/manual/en/language.operators.comparison.php
Additionally, I suppose you have an indexed array, although you expect it to be an associative array:
The array() function is used to create an array.
In PHP, there are three types of arrays:
Indexed arrays - Arrays with numeric index
Associative arrays - Arrays with named keys
Multidimensional arrays - Arrays containing one or more arrays
Syntax
Syntax for indexed arrays:
array(value1,value2,value3,etc.);
Syntax for associative arrays:
array(key=>value,key=>value,key=>value,etc.);

How Does the any Method Work in Groovy?

I came across this bit of code:
n = args[0] as Long
[*n..1, n].any{ println ' '*it + '*'*(n - ~n - it*2) }
It's used for printing a tree form of structure. Like this:
*
***
*****
*******
*
(for n=4)
How does the code [*n..1,n] produce [4, 3, 2, 1, 4]?
How does any method works here? The Doc doesn't help me much. What is a predictive that can be passed to any(as mentioned in Doc's)?
Whats the use of any and how its handled in this case?
Q1a: * "unpacks" an array. .. creates a range. [] creates a collection.
Q1b: *n..1 unpacks [4,3,2,1] into its individual parts.
Q1c: [4,3,2,1,n] == [4,3,2,1,4]
Q2: I don't know why any was used here; each works just as well, and makes more sense in context. any does loop over the connection, so the println side-effect functions as intended.
Normally any would be used to determine if any collection elements met a criteria, for example:
[*n..1,n].any { it > 10 } // Returns false, no elements are > 10
[*n..1,n].any { it == 3 } // Returns true, because at least one element is 3
The last statement of the closure is used to determine if each item meets the criteria. println returns null, so any will return false. The value is unused and discarded.
The only reason I can think of that someone might have used any is to avoid seeing the return value of each in the console. each returns the original collection.
1) n..1 is called a range literal, it creates a groovy.lang.Range object that decrements by 1 from n to 1. This is then merged into the surrounding list context using the "Spread operator (*)"
2) the any method is defined in DefaultGroovyMethods and it is a predicate function that returns true if an element in a collection satisfies the supplied predicate closure. In this example, the code doesn't check the return value, so original other could have produced the same output using an each call instead.

Resources