Operate multiple arrays simultaneously - arrays

I am using as3 in adobe animate to create a video game.
I have created multiple arrays with movie clips e.g.
var A:Array [mc1, mc2, mc3]
var B:Array [mc4, mc5, mc6]
var C:Array [mc7, mc8, mc9]
var anObject:DisplayObject;
How can I operate all movie clips in all arrays simultaneously?
I have tried this:
mc_Player.addEventListener(MouseEvent.CLICK, Change_Position);
function Change_Position (event:MouseEvent):void
{
{for each (anObject in A) & (anObject in B) & (anObject in C) // how can I get this right?
{anObject.x -= 100;
}}
}
I am also trying to understand if there is a way to operate all movie clips in my project simultaneously without using arrays.
e.g.
mc_Player.addEventListener(MouseEvent.CLICK, Change_Position);
function Change_Position (event:MouseEvent):void
{
{all movie_clips // how can I get this right?
{anObject.x -= 100;
}}
}
Thank you.

There's no such thing as simultaneous in programming (well, unless you are multi-threading with the perfect sync, which is not an AS3 story at all).
There are to ways to get close to that simultaneous thing:
Put all the objects into a single container. You will be able to change x and y of that container so all the in-laid objects will change their visible positions at once. The downside is that you cannot rotate or scale them individually (think of them as clipped to a board and imagine you rotate the whole board), or you won't be able to move half of them.
Arrays and loops. You iterate through all the items one by one, very fast. It looks simultaneous from the outside, but it never is.
All that said, in order to achieve the things you want you need to figure a way to put all the objects you want to process simultaneously into a single Array and then do the thing you want on them.
Case №1: many Arrays to one.
// This methods takes a mixed list of items and Arrays
// and returns a single flattened list of items.
function flatten(...args:Array):Array
{
var i:int = 0;
// Iterate over the arguments from the first and on.
while (i < args.length)
{
if (args[i] is Array)
{
// These commands cut the reference to the Array
// and put the whole list of its elements instead.
aRay = [i,1].concat(args[i]);
args.splice.apply(args, aRay);
}
else
{
// The element is not an Array so let's just leave it be.
i++;
}
}
return args;
}
Then all you need to do is to get a single list out of your several Arrays:
var ABC:Array = flatten(A, B, C);
for each (var anObject:DisplayObject in ABC)
{
anObject.x -= 100;
}
Performance-wise, it is a good idea to pre-organize, if logically possible, these Arrays so you don't have to compile them each time you need to process all the objects. Simply, if sometimes you would need A + B, and sometimes B + C, and sometimes A + B + C, just create them and have them ready. If you know what you are going to deal with, you won't even need that complicated flatten method:
var AB:Array = A.concat(B);
var BC:Array = B.concat(C);
var ABC:Array = A.concat(B).concat(C);
Case №2: all the children at once. As I already explained in my answer to one of your previous questions, you can iterate over all the children of a certain container, and you can put them into — guess what — Array for later use. Also, you can filter the objects while doing so and put only those ones you actually want to be there.
var ALL:Array = new Array;
// Iterate over the amount of children of "this" container.
for (var i:int = 0; i < numChildren; i++)
{
// Obtain a reference to the child at the depth "i".
var anObject:DisplayObject = getChildAt(i);
// Here go possible criteria for enlisting.
// This will ignore texts and buttons.
// if (anObject is MovieClip)
// This will take only those with names starting with "mc".
if (anObject.name.substr(0, 2) == "mc")
{
ALL.push(anObject);
}
}
// Viola! You have all the objects you want in a single Array
// so you can bulk-process them now, which is ALMOST simultaneous.

Related

Multidimensional array not letting me assign values through loop?

I have a small bit of code that looks like this:
func initAllLabels() {
var scoreLabels:[[[SKLabelNode]]] = []
for (var x = 0; x < modesInGame; x++) {
for (var y = 0; y < levelsInMode; y++) {
for (z = 0; z < labelsInLevel; z++) {
scoreLabels[x][y][z] = SKLabelNode(fontNamed: "Font")
}
}
}
}
So what I am trying to do is store all my labels for every game mode. The reason I'm trying to use a multidimensional array is because I will have several labels per level (3-5) and I would like to access them like this:
updateText(scoreLabels[currentMode][currentLevel][thisLabel])
And accessing all the labels for the current label like this:
for label in labelsInLevel:
label.hidden = false
The problem is that when I try to create all my labels at the start of the game in initAllLabels, I get an "index out of range" error at the first run in the loop (index: 0). I think the problem is because I need to "append" to the array before setting its contents, is this right? How would I accomplish this in an array structure like mine?
You need to initialize the array to a given size before updating items at positions within it. It might help to start with the single-dimensional case:
var labels: [SKLabelNode] = [] // creates an empty array
// since the array is empty, this will generate an index out of range error:
labels[0] = SKLabelNode(fontNamed: "Font")
Instead you need to extend the array with the elements you want to add. For example,
for _ in 0..<labelsInLevel {
labels.append(SKLabelNode(fontNamed: "Font"))
}
(the _ means “I don’t care about the actual number of each iteration - normally if you wanted to know this was the ith time around the loop you’d write for i in 0..<n)
There are nicer ways to do this though. But be careful with one of them, the initializer for Array that takes a count and a repeatedValue:
let labels = Array(count: labelsInLevel, repeatedValue: SKLabelNode(fontNamed: "Font”))
SKLabelNode is a reference type. That means that a variable only refers to an instance, and assigning one variable to another only copies the reference. So for example:
let variableOne = SKLabelNode(fontNamed: "Foo")
let variableTwo = variableOne
// variableTwo now refers to the same instance of SKLabelNode
variableTwo.fontName = "Bar"
print(variableOne)
// fontName will now be “Bar” even though this was
// done via variableTwo
You get the same effect with the repeatedValue code above. The label is created once, and the same reference to it is inserted multiple times. Change a property on one label in the array, and you change them all. Note the for loop version does not have this problem. Every time around the loop, a new SKLabelNode instance will be created. They won’t be shared.
An alternative to the repeatedValue initializer, that creates without using a for loop is to use map:
(0..<labelsInLevel).map { _ in SKLabelNode(fontNamed: "Font") }
Here, just like in the for loop version, a new SKLabelNode instance is created every time.
(again, we use the _ to indicate we don’t care about the number of the iteration)
Finally, to create the nested multidimensional arrays with the loops inside, you can run map multiple times:
var scoreLabels =
(0..<modesInGame).map { _ in
(0..<levelsInMode).map { _ in
(0..<labelsInLevel).map { _ in
SKLabelNode(fontNamed: "Font")
}
}
}
You need to initialize the 3D array like this if you want all SKLabelNode to point at different SKLabelNodes :
func initAllLabels() {
var scoreLabels = [[[SKLabelNode]]](count: modesInGame, repeatedValue:
[[SKLabelNode]](count: levelsInMode, repeatedValue:
(0..< labelsInLevel).map { _ in SKLabelNode(fontNamed: "Font") }))
}
The repeatedValue is what you are storing in the cells (type or value) and the count represent the number of times you want to store it in your array.
PS: This answer was tested with Xcode Playground and works perfectly fine.
I edited my answer following Airspeed Velocity's comment.

As3 Best solution about arrays

Let me cut to the main issue, I have a grid which is 50 by 50. And I need a way of having a true or false variable for each cell in the grid and the default value would be false, every time the method is called.
I need the array so I can see which cells I have visited so I don't need to revisited them for my path finding system that I'm working on .
But currently I have a double array[] [] which I need to loop every time I use this method. (up to 3 times a second but mostly never) which means looping 2500 value. Which doesn't sound very good. What would be the best solution, is this the best solution or am I missing something stupid.
Hope you can help and point me into the right direction.
Another possible improvement is using a single-dimensional vector, maybe wrapped into a class, that will contain 2500 elements and its indexes would mean (width*50+height). Like this:
private var _visited:Vector.<Boolean>;
function checkVisited(x:int,y:int):Boolean {
return _visited(x*50+y); // x and y are in 0-49 range
}
Vectors can be two-dimensional should you need them, you declare vector of vectors like this:
var _visited:Vector.<Vector.<Boolean>>;
Initialize with pushing the filled Vector.<Boolean> once, then just change the elements as you do with a normal array.
The main advantage of vectors is that they are solid, that is, if there are 50 elements in a vector, you are sure that there exists a value at any index from 0 to 49 (even if null, or NaN in case of Numbers), this also makes internal processing of vectors easier, as the Flash engine can calculate proper memory location by just using the index and the link to the vector, which is faster than first referencing the array about whether there is a value at that index, if yes, get its memory location, then reference.
From my experience of making tile based games with different grids I usually have a Tile class, that will contain all your necessary values, most typical would be:
posX:int
posY:int
isChecked:Boolean
You can add as many as you need for your app.
Then I have a Grid class that will create you grid and have some useful methods like giving neighbor tiles.
In the Grid class I make the grid this way:
public var tileLineArray:Vector.<Tile>;
public var tile2dArray:Vector.<Vector.<Tile>>;
public function makeGrid(w:int, h:int):void
{
tileLineArray = new Vector.<Tile>();
tile2dArray = new Vector.<Vector.<Tile>>();
for (var i:int = 0; i < gridWidth; i++)
{
var rowArray:Vector.<Tile> = new Vector.<Tile>();
for (var j:int = 0; j < gridHeight; j++)
{
var t:Tile = new Tile();
t.posX = i;
t.posY = j;
tileLineArray.push(t);
rowArray.push(t);
}
tile2dArray.push(rowArray);
}
}
What it will give you is that you can access tiles in a single line to by coordinates x,y;
var myTile:Tile = tileLineArray[lineID];
var myTile:Tile = tile2dArray[targetX][targetY];
I use Vectors in this example as they outperform Arrays and you keep the type of the stored object intact.
It is not a problem for Flash to loop through the array; if you want improve performance, break the loop if you've done all what you wanted with it, continue the loop if the tile does not meet the requirements and you don't need to process it.
Also, having a 2d array can improve performance, since you can process only the area of the array that you need.
One more advice is not to be afraid to make X more smaller arrays to store some data from the bigger array and loop trough the small ones. As the data of the arrays is not a primitive (int, uint etc.) but a Class, it will hold a pointer/reference to the object, so you're not actually making copies of the objects every time.

Multidimensional array of texture in Unity3d

I have some textures those i need to show in diffrent scrollviews dynamically.
for naming convention i am using below approach
texturename24
texturename - This prefix is associated with every texture.
2- This represents a particular category of texture i.e. dot. stripes , etc.
4 - This is for serial number of texture
with below lines of code i am fetching textures from resource folder
var textures : Object[];
textures = Resources.LoadAll("TextureFolder");
i need to make array for every pattern suppose texturename00,01,02,03 should be in one array and texturename10,11,12,13 should be other array, here i need to crate dynamic array on the basis of patterns count.
I've been thinking about this for the past few days and basically I can't think of a single use case for what you're doing that wouldn't be better solved by implementing a simple sprite sheet solution. You could also acquire any of the hundreds of available solutions out there that implement sheet-based solutions to this problem.
Loading a texture is not a trivial task for the engine and whenever possible you want to limit your inode access. Using a single Atlas texture that has all of your sub-images placed at regular intervals would be one easy solution. You would then iterate over the map and assign mainTextureOffsets for each material that uses the same image. You can also use irregular placement but for that you'll need some kind of transient medium to store the offset values.
Rather than storing the texture2d in memory in this solution; you will instead be storing Vector2 structs which are far less memory intense. If you have a use case that falls outside the parameters of what you can do with sprite sheets (Atlas maps) you'll have to detail it fully here so we can help you further but I'm fairly certain this will get you to a solution in the most efficacious manner.
FIDDLE DEMO
var outer_array = [];
var inner_array = [];
for (var i = 0; i < 35; i++) {
inner_array.push(i);
if (inner_array.length == 4) {
outer_array.push(inner_array);//push the array[0,1,2,3] and so on in to outer array.
inner_array = [];//this will empty my array
i = i + 6;//to jump from 4 to 10,14 to 20 and so on..
}
}
console.log(outer_array)
I find a way to do this.
Declare a 2d array and set row and column to 100 and use below lines of code.
noOfPattern and noOfColors are integers to get the count of row and columns of 2d array.
var arrAll = new Texture2D[100,100];
for(var p=0 ; p<100 ; p++){
TextureP = Resources.Load("FolderName/"+"ImageName"+p+0);
if(TextureP !=null){
for(var q=0 ; q<100 ; q++){
TextureQ = Resources.Load("FolderName/"+"ImageName"+p+q);
if(TextureQ !=null){
arrAll[p,q] = TextureQ;
noOfColors = q;
}
}
noOfPattern = p;
}
}

AS3 make an array of movieclip moves constantly. (this array constantly increases in size)

ActionScript 3.0
I got this bullet_array.
and it pushes new bullet everytime I pressed spacebar.
There's this "for loop", which works - only when I pressed spacebar.
but I wanted the bullets to constantly move.
the 'for loop' is inside update(), which is from Event.ENTER_FRAME
so technically, the for loop should constantly be looping (i think), but it only went through ONCE, and only after the array increases in size. And it only worked on the new object, and didn't touch the old object.
public function update(evt:Event = null)
{
stage.focus = stage;
//fire = true is set by spacebar
if (fire == true)
{
var snowball:MovieClip = new Snowball;
snowball.x = (mcPlayer.x);
snowball.y = (mcPlayer.y - 5);
snowballArray.push(snowball);
SBAlength = +1; //stands for snowballArray's length
addChild(snowball);
fire = false;
}
for (var i = SBAlength - 1; i >= 0; i--)
{
snowballArray[i].y -= snowballSpd; //snowballSpd is already declared as 5
for (var j = snowmanArray.length - 1; j>=0; j--)
{
for (var k = numberArray.length -1; k>0; k--)
{
if (snowballArray[i].hitTestObject(snowmanArray[j]))
{
if (snowmanArray[j].hitTestObject(numberArray[k]))
{
bosslife -= numberArray[k];
numberArray[k].splice(k,1);
}
snowballArray[i].gotoAndPlay("hit");
snowmanArray[j].splice(j,1);
break;
}
if(numberArray[k] >= 0)
{
numberArray[k].splice(k,1);
randomNo= Math.floor(Math.random()*(max-min+1))+min;
numberArray[k].push(randomNo);
}
snowmanArray[j].txtNumber.text = numberArray[j];
}
}
There may be other issues here, but:
Maintaining the array length
SBAlength = +1; // Sets your length to 1
Instead use:
SBAlength += 1; // Increases your length by 1
But really, you might as well use the array's length property in the loop, instead of maintaining SBALength (and risking it getting out of sync due to some future code):
for (var i = snowballArray.length - 1; i >= 0; i--)
Manipulating arrays
Also (don't think this is related to your problem, but it will certainly cause errors), in your inner loop, you're constantly doing things like this:
snowmanArray[j].splice(j,1);
numberArray[k].push(randomNo);
// etc.
That would only work if the items in numberArray and snowmanArray are themselves arrays - not sure if they are, but doesn't seem like it, since you're also using the items as numbers:
bosslife -= numberArray[k];
The first statement is asking to remove an item from an array stored in snowmanArray[j] - not removing an item from snowmanArray itself. If you want to remove an item from snowmanArray, you'd do snowmanArray.splice(j, 1).
In the same way, to add an item to numberArray, you'd do numberArray.push(randomNo), rather than numberArray[k].push(randomNo).
Manipulating arrays inside loops etc.
It's fine to e.g. remove the current array item while iterating over that array - but only as long as you do it in the way you do, starting from the end and going backwards. However...
After doing (or rather, intending to do) this if the snowman was hit:
snowmanArray.splice(j,1);
... you're later doing:
snowmanArray[j].txtNumber.text = numberArray[j];
I.e. you remove the snowman from the array, but then later on, you try to get the array item you just removed. You need to be sure that snowmanArray[j] still exists before you address it.
Array item types
You're mostly using numberArray as an array of int (or Number). Except here:
snowmanArray[j].hitTestObject(numberArray[k])
You can't hitTestObject against an int/Number. Not sure what the line is supposed to do, but the object you hit test against needs to be a DisplayObject (e.g. a MovieClip).
Erm... after lots of tracing around and stuff,
i figure that the main problem isn't with the array nor the splicing (though my codes is wrong -but it didn't work even if i commented away those codes), but that i place > instead of < to check bosslife, so it keep resetting the level, so snowballArray keeps becoming a new Array, hence the array.length didn't work, and using SBAlength gives some kinda weird error while inside the for loop.

Why should I use foreach instead of for (int i=0; i<length; i++) in loops?

It seems like the cool way of looping in C# and Java is to use foreach instead of C style for loops.
Is there a reason why I should prefer this style over the C style?
I'm particularly interested in these two cases, but please address as many cases as you need to explain your points.
I wish to perform an operation on each item in a list.
I am searching for an item in a list, and wish to exit when that item is found.
Imagine that you're the head chef for a restaurant, and you're all preparing a huge omelette for a buffet. You hand a carton of a dozen eggs to each of two of the kitchen staff, and tell them to get cracking, literally.
The first one sets up a bowl, opens the crate, grabs each egg in turn - from left to right across the top row, then the bottom row - breaking it against the side of the bowl and then emptying it into the bowl. Eventually he runs out of eggs. A job well done.
The second one sets up a bowl, opens the crate, and then dashes off to get a piece of paper and a pen. He writes the numbers 0 through 11 next to the compartments of the egg carton, and the number 0 on the paper. He looks at the number on the paper, finds the compartment labelled 0, removes the egg and cracks it into the bowl. He looks at the 0 on the paper again, thinks "0 + 1 = 1", crosses out the 0 and writes 1 on the paper. He grabs the egg from compartment 1 and cracks it. And so on, until the number 12 is on the paper and he knows (without looking!) that there are no more eggs. A job well done.
You'd think the second guy was a bit messed in the head, right?
The point of working in a high-level language is to avoid having to describe things in a computer's terms, and to be able to describe them in your own terms. The higher-level the language, the more true this is. Incrementing a counter in a loop is a distraction from what you really want to do: process each element.
Further to that, linked-list type structures can't be processed efficiently by incrementing a counter and indexing in: "indexing" means starting over counting from the beginning. In C, we can process a linked list that we made ourselves by using a pointer for the loop "counter" and dereferencing it. We can do this in modern C++ (and to an extent in C# and Java) using "iterators", but this still suffers from the indirectness problem.
Finally, some languages are high-enough level that the idea of actually writing a loop to "perform an operation on each item in a list" or "search for an item in a list" is appalling (in the same way that the head chef shouldn't have to tell the first kitchen staff member how to ensure that all the eggs are cracked). Functions are provided that set up that loop structure, and you tell them - via a higher-order function, or perhaps a comparison value, in the searching case - what to do within the loop. (In fact, you can do these things in C++, although the interfaces are somewhat clumsy.)
Two major reasons I can think of are:
1) It abstracts away from the underlying container type. This means, for example, that you don't have to change the code that loops over all the items in the container when you change the container -- you're specifying the goal of "do this for every item in the container", not the means.
2) It eliminates the possibility of off-by-one errors.
In terms of performing an operation on each item in a list, it's intuitive to just say:
for(Item item: lst)
{
op(item);
}
It perfectly expresses the intent to the reader, as opposed to manually doing stuff with iterators. Ditto for searching for items.
foreach is simpler and more readable
It can be more efficient for constructions like linked lists
Not all collections support random access; the only way to iterate a HashSet<T> or a Dictionary<TKey, TValue>.KeysCollection is foreach.
foreach allows you to iterate through a collection returned by a method without an extra temporary variable:
foreach(var thingy in SomeMethodCall(arguments)) { ... }
One benefit for me is that it's less easy to make mistakes such as
for(int i = 0; i < maxi; i++) {
for(int j = 0; j < maxj; i++) {
...
}
}
UPDATE:
This is one way the bug happens. I make a sum
int sum = 0;
for(int i = 0; i < maxi; i++) {
sum += a[i];
}
and then decide to aggregate it more. So I wrap the loop in another.
int total = 0;
for(int i = 0; i < maxi; i++) {
int sum = 0;
for(int i = 0; i < maxi; i++) {
sum += a[i];
}
total += sum;
}
Compile fails, of course, so we hand edit
int total = 0;
for(int i = 0; i < maxi; i++) {
int sum = 0;
for(int j = 0; j < maxj; i++) {
sum += a[i];
}
total += sum;
}
There are now at least TWO mistakes in the code (and more if we've muddled maxi and maxj ) which will only be detected by runtime errors. And if you don't write tests... and it's a rare piece of code - this will bite someone ELSE - badly.
That is why it's a good idea to extract the inner loop into a method:
int total = 0;
for(int i = 0; i < maxi; i++) {
total += totalTime(maxj);
}
private int totalTime(int maxi) {
int sum = 0;
for(int i = 0; i < maxi; i++) {
sum += a[i];
}
return sum;
}
and it's more readable.
foreach will perform identically to a for in all scenarios[1], including straightforward ones such as you describe.
However, foreach has certain non-performance-related advantages over for:
Convenience. You do not need to keep an extra local i around (which has no purpose in life other than facilitating the loop), and you do not need to fetch the current value into a variable yourself; the loop construct has already taken care of that.
Consistency. With foreach, you can iterate over sequences which are not arrays with the same ease. If you want to use for to loop over a non-array ordered sequence (e.g. a map/dictionary) then you have to write the code a little differently. foreach is the same in all cases it covers.
Safety. With great power comes great responsibility. Why open opportunities for bugs related to incrementing the loop variable if you don't need it in the first place?
So as we see, foreach is "better" to use in most situations.
That said, if you need the value of i for other purposes, or if you are handling a data structure that you know is an array (and there is an actual specific reason for it being an array), the increased functionality that the more down-to-the-metal for offers will be the way to go.
[1] "In all scenarios" really means "all scenarios where the collection is friendly to being iterated", which would actually be "most scenarios" (see comments below). I really think that an iteration scenario involving an iteration-unfriendly collection would have to be engineered, however.
You should probably consider also LINQ if you are targeting C# as a language, since this is another logical way to do loops.
By perform an operation on each item in a list do you mean modify it in place in the list, or simply do something with the item (e.g. print it, accumulate it, modify it, etc.)? I suspect it is the latter, since foreach in C# won't allow you to modify the collection you are looping over, or at least not in a convenient way...
Here are two simple constructs, first using forand then using foreach, which visit all strings in a list and turn them into uppercase strings:
List<string> list = ...;
List<string> uppercase = new List<string> ();
for (int i = 0; i < list.Count; i++)
{
string name = list[i];
uppercase.Add (name.ToUpper ());
}
(note that using the end condition i < list.Count instead of i < length with some precomputer length constant is considered a good practice in .NET, since the compiler would anyway have to check for the upper bound when list[i] is invoked in the loop; if my understanding is correct, the compiler is able in some circumstances to optimize away the upper bound check it would normally have done).
Here is the foreach equivalent:
List<string> list = ...;
List<string> uppercase = new List<string> ();
foreach (name in list)
{
uppercase.Add (name.ToUpper ());
}
Note: basically, the foreach construct can iterate over any IEnumerable or IEnumerable<T> in C#, not just over arrays or lists. The number of elements in the collection might therefore not be known beforehand, or might even be infinite (in which case you certainly would have to include some termination condition in your loop, or it won't exit).
Here are a few equivalent solutions I can think of, expressed using C# LINQ (and which introduces the concept of a lambda expression, basically an inline function taking an x and returning x.ToUpper () in the following examples):
List<string> list = ...;
List<string> uppercase = new List<string> ();
uppercase.AddRange (list.Select (x => x.ToUpper ()));
Or with the uppercase list populated by its constructor:
List<string> list = ...;
List<string> uppercase = new List<string> (list.Select (x => x.ToUpper ()));
Or the same using the ToList function:
List<string> list = ...;
List<string> uppercase = list.Select (x => x.ToUpper ()).ToList ();
Or still the same with type inference:
List<string> list = ...;
var uppercase = list.Select (x => x.ToUpper ()).ToList ();
or if you don't mind getting the result as an IEnumerable<string> (an enumerable collection of strings), you could drop the ToList:
List<string> list = ...;
var uppercase = list.Select (x => x.ToUpper ());
Or maybe another one with the C# SQL-like from and select keywords, which is fully equivalent:
List<string> list = ...;
var uppercase = from name in list
select name => name.ToUpper ();
LINQ is very expressive and very often, I feel that the code is more readable than a plain loop.
Your second question, searching for an item in a list, and wish to exit when that item is found can also be very conveniently be implemented using LINQ. Here is an example of a foreach loop:
List<string> list = ...;
string result = null;
foreach (name in list)
{
if (name.Contains ("Pierre"))
{
result = name;
break;
}
}
Here is the straightforward LINQ equivalent:
List<string> list = ...;
string result = list.Where (x => x.Contains ("Pierre")).FirstOrDefault ();
or with the query syntax:
List<string> list = ...;
var results = from name in list
where name.Contains ("Pierre")
select name;
string result = results.FirstOrDefault ();
The results enumeration is only executed on demand, which means that effectively, the list will only be iterated until the condition is met, when invoking the FirstOrDefault method on it.
I hope this brings some more context to the for or foreach debate, at least in the .NET world.
As Stuart Golodetz answered, it's an abstraction.
If you're only using i as an index, as opposed to using the value of i for some other purpose like
String[] lines = getLines();
for( int i = 0 ; i < 10 ; ++i ) {
System.out.println( "line " + i + lines[i] ) ;
}
then there's no need to know the current value of i, and being able to just leads to the possibility of errors:
Line[] pages = getPages();
for( int i = 0 ; i < 10 ; ++i ) {
for( int j = 0 ; j < 10 ; ++i )
System.out.println( "page " + i + "line " + j + page[i].getLines()[j];
}
As Andrew Koenig says, "Abstraction is selective ignorance"; if you don't need to know the details of how you iterate some collection, then find a way to ignore those details, and you'll write more robust code.
Reasons to use foreach:
It prevents errors from creeping in (e.g. you forgot to i++ in the for loop) that could cause the loop to malfunction. There are lots of ways to screw up for loops, but not many ways to screw up foreach loops.
It looks much cleaner / less cryptic.
A for loop may not even be possible in some cases (for example, if you have an IEnumerable<T>, which cannot be indexed like an IList<T> can).
Reasons to use for:
These kinds of loops have a slight performance advantage when iterating over flat lists (arrays) because there is no extra level of indirection created by using an enumerator. (However, this performance gain is minimal.)
The object you want to enumerate does not implement IEnumerable<T> -- foreach only operates on enumerables.
Other specialized situations; for example, if you are copying from one array to another, foreach will not give you an index variable that you can use to address the destination array slot. for is about the only thing that makes sense in such cases.
The two cases you list in your question are effectively identical when using either loop -- in the first, you just iterate all the way to the end of the list, and in the second you break; once you have found the item you are looking for.
Just to explain foreach further, this loop:
IEnumerable<Something> bar = ...;
foreach (var foo in bar) {
// do stuff
}
is syntactic sugar for:
IEnumerable<Something> bar = ...;
IEnumerator<Something> e = bar.GetEnumerator();
try {
Something foo;
while (e.MoveNext()) {
foo = e.Current;
// do stuff
}
} finally {
((IDisposable)e).Dispose();
}
If you are iterating over a collection that implements IEnumerable, it is more natural to use foreach because the next member in the iteration is assigned at the same time that the test for reaching the end is done. E.g.,
foreach (string day in week) {/* Do something with the day ... */}
is more straightforward than
for (int i = 0; i < week.Length; i++) { day = week[i]; /* Use day ... */ }
You can also use a for loop in your class's own implementation of IEnumerable. Simply have your GetEnumerator() implementation use the C# yield keyword in the body of your loop:
yield return my_array[i];
Java has both of the loop types you have pointed to. You can use either of the for loop variants depending on your need. Your need can be like this
You want to rerun the index of your search item in the list.
You want to get the item itself.
In the first case you should use the classic (c style) for loop. but in the second case you should use the foreach loop.
The foreach loop can be used in the first case also. but in that case you need to maintain your own index.
If you can do what you need with foreach then use it; if not -- for example, if you need the index variable itself for some reason -- then use for. Simple!
(And your two scenarios are equally possible with either for or foreach.)
one reason not to use foreach at least in java is that it will create an iterator object which will eventually be garbage collected. Thus if you are trying to write code that avoids garbage collection it is better to avoid foreach. However, I believe it is ok for pure arrays because it doesn't create an iterator.
I could think of several reasons
you can't mess up indexes, also in mobile environment you do not have compiler optimizations and lousily written for loop could do several bounderay checks, where as for each loop does only 1.
you can't change data input size (add / remove elements) while iterating it. Your code does not brake that easily. If you need to filter or transform data, then use other loops.
you can iterate over data structures, that can't be accesses by index, but can be crawled over. For each just needs that you implement iterable interface (java) or extend IEnumerable (c#).
you can have smaller boiler plate, for example when parsing XML it's difference between SAX and StAX, first needs in-memory copy of the DOM to refer to an element latter just iterates over data (it is not as fast, but it is memory efficient)
Note that if you are searching for an item in the list with for each, you most likely are doing it wrongly. Consider using hashmap or bimap to skip the searching all together.
Assuming that programmer want's to use for loop as for each using iterators, there exists a common bug of skipping elements. So in that scene it is more safer.
for ( Iterator<T> elements = input.iterator(); elements.hasNext(); ) {
// Inside here, nothing stops programmer from calling `element.next();`
// more then once.
}
Talking about clean code, a foreach statement is much quicker to read than a for statement!
Linq (in C#) can do much the same, but novice developers tend to have a hard time reading them!
It looks like most items are covered... the following are some extra notes that I do not see mentioned regarding your specific questions. These are hard rules as opposed to style preferences one way or the other:
I wish to perform an operation on each item in a list
In a foreach loop, you can not change the value of the iteration variable, so if you are looking to change the value of a specific item in your list you have to use for.
It is also worth noting that the "cool" way is now to use LINQ; there are plenty of resources you can search for if you are interested.
foreach is order of magnitude slower for implementation heavy collection.
I have proof. These are my findings
I used the following simple profiler to test their performance
static void Main(string[] args)
{
DateTime start = DateTime.Now;
List<string> names = new List<string>();
Enumerable.Range(1, 1000).ToList().ForEach(c => names.Add("Name = " + c.ToString()));
for (int i = 0; i < 100; i++)
{
//For the for loop. Uncomment the other when you want to profile foreach loop
//and comment this one
//for (int j = 0; j < names.Count; j++)
// Console.WriteLine(names[j]);
//for the foreach loop
foreach (string n in names)
{
Console.WriteLine(n);
}
}
DateTime end = DateTime.Now;
Console.WriteLine("Time taken = " + end.Subtract(start).TotalMilliseconds + " milli seconds");
And I got the following results
Time taken = 11320.73 milli seconds (for loop)
Time taken = 11742.3296 milli seconds (foreach loop)
A foreach also notifies you if the collection you're enumerating through changes (i.e. you HAD 7 items in your collection...until another operation on a separate thread removed one and now you only have 6 #_#)
Just wanted to add that whoever thinks that foreach gets translated into for and therefore has no performance difference is dead wrong. There are many things that happen under the hood, i.e. the enumeration of the object type which is NOT in a simple for loop. It looks more like an iterator loop:
Iterator iter = o.getIterator();
while (iter.hasNext()){
obj value = iter.next();
...do something
}
which is significantly different than a simple for loop. If you dont understand why, then lookup vtables. Furthermore, who knows whats in the hasNext function? For all we know it could be:
while (!haveiwastedtheprogramstimeenough){
}
now advance
Exageration aside, there are function of unknown implementation and efficiency being called. Since compilers dont optimize accross function boundaries, there is NO optimization happening here, just your simple vtable lookup and function call. This is not just theory, in practice, i have seen significant speedups by switching from foreach to for on the standard C# ArrayList. To be fair, it was an arraylist with about 30,000 items, but still.

Resources