Lesson Objectives
At the end of this lesson, you will know…
- How to use a “foreach” to work with the objects inside lists
Another common thing you’ll need to do is look at the objects contained in a list. Maybe you’ll need to total up some values, or see if you have a certain object in the list.
This is where you can use “foreach” loop. Think of it as, “I want to do ‘something’ for each object in this list.”
Using a foreach to see if an item exists in a list
In the World class, we already have some functions with foreach.
Here’s the code for the ItemByID() function that finds an item, based on its ID:
public static Item ItemByID(int id) { foreach(Item item in Items) { if(item.ID == id) { return item; } } return null; }
We already have the Items list created as a class-level variable and populated from the constructor. This function will find the item with the same ID as the parameter that was passed in, and return it to the part of the program that called this function.
Here is what’s happening in the parentheses after the “foreach”:
The “in Items”, at the end, is where you say which list you want to look through. In this case, it’s the “Items” list.
The “Item” is the datatype of the objects in this list.
And, the “item” is the variable that will hold each object from the list, when the code between the curly braces is run.
So, the general pattern for a foreach is:
foreach(DataType variableName in listName)
When this code runs, it will take the first object from the “Items” list, and assign it to the “item” variable.
Then it will check to see if the “ID” property of the current “item” variable matches the “id” that was passed in as a parameter to the function. If it does match, the function returns that item object. If it doesn’t match, the foreach will get the next object from the list, assign it to the “item” variable, and then check it.
If the function goes through all the item objects in the Items list, and none of them match, the “foreach” loop will finish and the rest of the code in the function will be run.
In this case, the only code in the rest of the function is “return null” (nothing/empty).
Note 1: Returning null is generally not a good idea. The code that called this function is expecting an “Item” object returned, and now it also needs to handle receiving a null.
This is one of those things we’re doing to keep it simple for these tutorials that you probably wouldn’t do in a “real” program.
Note 2: .Net has something called LINQ that also works with lists. It lets you perform the same logic, but often in a single line of code. However, for some people, it takes a little time to figure out how to work with it.
Here’s a function to show you how LINQ can be much shorter than using a foreach.
public void CalculateAverage() { // Create and populate the list of numbers List<double> values = new List<double>(); values.Add(1); values.Add(5); values.Add(21); // Calculating the average, using a foreach double total = 0; double counter = 0; foreach(double value in values) { total = (total + value); counter = (counter + 1); } double average = (total / counter); // Calculating the average, using LINQ double linqAverage = values.Average(); }
In the first few lines, we create a list of “double”s (double-precision numbers, that can have decimal values) and add values to it.
Next, we calculate the average value with a “foreach”.
To do this, we need to have some variables to hold the total of the values in the list and to see how many items are in the list. Then we calculate the average by dividing the total by the number of values (for this sample, I’m not worrying about the list being empty, which would result in a “divide by zero” error).
That code takes up 10 lines in the function.
The final line is how you can get the average value from a list, using LINQ. It’s one line.
This is a simple demo of one LINQ function. They can get more complex, which is why I’m not covering them in this tutorial.
Summary
Now you can work with the lists we have in the game – the player’s inventory and quest lists, and the list of locations, items, monsters, and quests in the World class.
Source code for this lesson
There is no code for this lesson
Next lesson: Lesson 15.1 – Getting random numbers for the game
Previous lesson: Lesson 14.2 – If statements
All lessons: Learn C# by Building a Simple RPG Index
Hello,
Is there a place where I could learn LINQ. In my understanding, LINQ has its own syntax and you can query multiple data sources. Correct me if I am wrong.
A good resource is 101 LINQ Samples in C# – although, it uses the SQL-like format for its LINQ statements, and I prefer to use the lambda format (that is only my personal preference). You can use LINQ to query multiple data sources and do things such as Group, Distinct, Intersect, and Except.
Hey Scott.
This is lesson is very clear, but i have a question about the double foreach loop you use in a next lesson. this chapter just seems more appropriate to ask it in.
If i loot monsters i wanne compare the list with items a monster can drop(MonsterLoot) with the list of items the player has (PlayerInventory)
If a monsterloot matches an item in the inventory, i wanne change the amount of that item in the inventory (instead of adding another object of that object). If its not a match i wanne add the monsterloot item to the playerinventory list.
here is what i have so far
//method that will execute above
public void CheckInventoryAndAddMonsterLoot(Monster monster)
foreach(Item monsterItem in monster.MonsterLoot) //list monster
{
foreach(Item inventoryItem in PlayerInventory) //list player
{
if (inventoryItem.ItemId == monsterItem.ItemId)
{
inventoryItem.ItemAmount += monsterItem.ItemAmount;
//break a
}
//break b
}
//break c
}
// return null, but i use void method so its not required(allowed)
Ok so my question. Im realy confused where to put breaks here and what they do.
if i use break a, it would cancel the foreach loop if it finds an item. But will it still check the other items in list monsters? (does it cancel both foreach loops or just the first)
break b is just bad? it will cancel the loop after checking only one item in list player?
break c is same as break b but will cancel after first item in list monster?
Where would i insert the line PlayerInventory.Add(monster.monsterItem)?
i cant put an else after the if statement couse it would add an item for every
inventoryItem.ItemId != monsterItem.ItemId
i hope this makes sense 🙂
grts
Hello Koro,
A “break” line will only exit out of one loop. So, “break a” will only stop looking for more items in the player’s inventory. It will continue to loop through the other items in the monster’s inventory.
To add a new item to the player’s inventory, you will need to use a new boolean variable. Inside the monsterItem loop, but before the PlayerInventory loop, you could create a line like this:
bool playerHadItem = false;
If you find the item in the player’s inventory, you set that variable to “true” – inside the if(inventoryItem.ItemId == monsterItem.ItemId) code. After looping through all the player’s inventory items (outside that loop), you can do a check if “playerHadItem” is still false. If it is, you add it to the player’s inventory.
Let me know if you try that and have any problems.
That worked.
Thank You very much.