C# FindIndex with parameters - c#

I'm currently patching my game that i recently released.
I have a list of a class, which is called AppliedEffects. The list made from that class is named appliedEffects.
I want to access this list and find a specific value in an index, and then make a bool true or false depending of if that value exists in the list. It is for a powerup system, where the list is all the powerups currently active. The code for shooting bullets for instance, will then search if there is an item in the list with the ID of 1, because that is the ID of having the double bullets powerup.
I have come this far, and only have a small problem:
int ndx = PlayerStatus.appliedEffects.FindIndex(PlayerStatus.FindAE(XX,1);
where XX is, I don't know what to put. I edited this:
int ndx = Books.FindIndex(FindComputer);
private static bool FindComputer(Book bk)
{
if (bk.Genre == "Computer")
{
return true;
}
else
{
return false;
}
}
Because in the code example, I could not send in which parameter I wanted to search for. The edited code looks like this:
public static bool FindAE(AppliedEffects ae, int id)
{
if (ae.id == id)
{
return true;
}
else
{
return false;
}
}
I create an int, that will get the index of the list where the item with the value of ID 1 exists, then if that value is 1, because the ID is 1, it will set a bool to true, and false if not.
I wanted to send in a parameter for the ID, which the example does not, so that I can reuse the function for other ID checks. But then when I enter the parameter, I don't know what to put as appliedEffect (that's why I put XX).
I have also tried this:
if (PlayerStatus.appliedEffects.Exists(x => x.id == 1))
{
PlayerStatus.doubleBullets = true;
}
which did not work, no clue why. I don't fully understand the concepts of the .Exists and .FindIndex, so maybe that's why I don't know how to use it.
Basically I just want to be able to check if there is an item with a specific ID in the list, so that the game will know that I have the specific powerup and can set a bool to true and then false.
Note: ID is not index, ID is an int in my AppliedEffects class that knows which powerup it is.
I'm a little tired so if there's any thoughts/concerns, please write in the thread, I'll subscribe to the thread.

Note that FindIndex will return -1 if the requested element is not found. Therefore, you would have to do something like so:
if(PlayerStatus.appliedEffects.FindIndex(ae => PlayerStatus.FindAE(ae, 1)) != -1)
{
PlayerStatus.doubleBullets = true;
}
It would probably make more sense in your situation to use Exists, like you noted. Try this:
if(PlayerStatus.appliedEffects.Exists(ae => PlayerStatus.FindAE(ae, 1)))
{
PlayerStatus.doubleBullets = true;
}

int ndx = PlayerStatus.appliedEffects.FindIndex(ae => PlayerStatus.FindAE(ae, 1));
The parameter to FindIndex is a method/lambda with one argument. In this case, a lambda is created which takes a single parameter ae, and returns FindAE(ae, 1).
The FindAE method isn't necessary. It might be easier to do this:
int ndx = PlayerStatus.appliedEffects.FindIndex(ae => ae.index == 1);

Related

Using Contains on an List in a different way

I have this code which i want to change:
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Contains(path)) {
MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
currNoPairs.Add(path);
}
}
In the If part i don't want to check the path i want to check the path.Name.
So how can i use the Contains method on the properties.
the goal is to sort out all folders that have not the same name in the list of Current Directory List and New Directory List.
See - IEnumerable<T>.Contains with predicate
Those functions that take "predicates" (boolean functions that signify a match) will let you do more complex checks. In this case, you can use them to compare sub-properties instead of the top-level objects.
The new code will look something like this:
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Any(newDir => newDir.Name == path.Name)) {
// TODO: print your error message here
currNoPairs.Add(path.Name);
}
}
In reply to your comment:
Okay i understood, but whats the diffrence between any and contains then?
List<T>.Contains
This method goes through each item in the list, seeing if that item is equal to the value you passed in.
The code for this method looks a little like this (simplified here for illustration):
for(var item in yourList) {
if(item.Equals(itemYouPassedIn) {
return true;
}
}
return false;
As you see, it can only compare top-level items. It doesn't check sub-properties, unless you are using a custom type that overrides the default Equals method. Since you're using the built in DirectoryInfo types, you can't override this Equals behavior without making a custom derived class. Since there's easier ways to do this, I wouldn't recommend this approach unless you need to do it in a ton of different places.
IEnumerable<T>.Any
This method goes through each item in the list, and then passes that item to the "predicate" function you passed in.
The code for this method looks a little like this (simplified for illustration):
for(var item in yourList) {
if(isAMatch(item)) { // Note that `isAMatch` is the function you pass in to `Any`
return true;
}
}
return false;
Your predicate function can be as complicated as you want it to be, but in this case, you'd just use it to check if the sub-properties are equal.
// This bit of code defines a function with no name (a "lambda" function).
// We call it a "predicate" because it returns a bool, and is used to find matches
newDir => newDir.Name == path.Name
// Here's how it might look like if it were defined as a normal function -
// this won't quite work in reality cause `path` is passed in by a different means,
// but hopefully it makes the lambda syntax slightly more clear
bool IsAMatch(DirectoryInfo newDir) {
return newDir.Name == path.Name;
}
Since you can customize this predicate every place that you use it, this could be a better tactic. I'd recommend this style until you are doing this exact check in a bunch of places in your code, in which case a custom class might be better.
Here is how you check for property Any
foreach (DirectoryInfo path in currDirs) {
if (!newDirs.Any(dir => dir.FullName == path.FullName)) {
MyLog.WriteToLog("Folder not Found: "+path.Name + "in New Folder. ",MyLog.Messages.Warning);
currNoPairs.Add(path);
}
}
And by the way, your code could be written in a better way like this
var currDirsConcrete = currDirs.ToArray();
var pathsNotFound = "Following paths were not found \r\n " + string.Join("\r\n", currDirsConcrete.Where(d => d.FullName != path.FullName).ToArray());
var pathsFound = currDirsConcrete.Where(d => d.FullName == path.FullName).ToArray();
MyLog.WriteToLog(pathsNotFound, MyLog.Messages.Warning);
Note: You can skip the first line currDirsConcrete if your currDirs is already an array or a list. I did this to avoid redetermining the enumerable.
I would use linq with except and implement a DirComparator
List<DirectoryInfo> resultExcept = currDirs.Except(newDirs, new DirComparator()).ToList();
Here the IEqualityComparer<DirectoryInfo>:
public class DirComparator : IEqualityComparer<DirectoryInfo> {
public bool Equals(DirectoryInfo x, DirectoryInfo y)
{
//Check whether the compared objects reference the same data.
if (Object.ReferenceEquals(x, y)) return true;
//Check whether any of the compared objects is null.
if (Object.ReferenceEquals(x, null) || Object.ReferenceEquals(y, null))
return false;
//Check whether the products' properties are equal.
return x.Name.equals(y.Name);
}
public int GetHashCode(DirectoryInfo dir)
{
//Check whether the object is null
if (Object.ReferenceEquals(dir, null)) return 0;
//Get hash code for the Name field if it is not null.
return dir.Name == null ? 0 : dir.Name.GetHashCode();
}
}
you could also use intersect if you want it the other way around.

Using an enum value to represent two enum values

Picture the scene.
public enum SaveStates
{
Saved, //Represents a successful save.
SavedWithChanges, //Represents a successful save, where records were modified
SavedWithoutChanges //Represents a successful save, but no records were modified
}
In this scenario, the enumeration can be considered Saved if it's SavedWithChanges or SavedWithoutChanges.
So if I were to have a variable like this:
SaveStates lastState = SaveStates.SavedWithoutChanges;
I'd ideally like to do something like this:
if (lastState == SaveStates.Saved)
{
//The state is saved, do something awesome.
}
I can of course do this:
if (lastState == SaveStates.SavedWithChanges || lastState == SaveStates.SavedWithoutChanges)
{
...
However this is a bit tedious and I can't assume that another developer is going to understand how to correctly use the enumeration.
Each enumeration is required as there may be an instance where we might want to do something specific in the event of a save where there has been no changes for example.
I'm open to alternative design ideas.
If what worries you is code readability, you can use a little extension method like this:
public static class SaveStatesExtension
{
public static bool IsSavedState(this SaveStates state) {
return state == SaveStates.SavedWithChanges ||
state == SaveStates.SavedWithoutChanges;
}
}
Then your usage example becomes:
if (lastState.IsSavedState())
{
//The state is saved, do something awesome.
}
Of course the Saved member in the enum is no longer needed in this case.
If you're going to do it with a Flags enum, you should make it self-documenting
[Flags]
public enum SaveStates
{
Saved = 1,
WithChanges = 2,
SavedWithoutChanges = Saved, // a bit pointless! Its the same as Saved
SavedWithChanges = Saved | WithChanges // has value "3"
}
And then, as per other answers
if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{
}
You can achieve this as follows, going by the example of the link I've posted under the question but using non-exclusive flag values. Note that both SavedWithChanges and SavedWithoutChanges contain the bit 1, assigned to Saved.
[Flags]
public enum SaveStates
{
Saved = 1,
SavedWithChanges = 3,
SavedWithoutChanges = 5
}
if ((lastState & SaveStates.Saved) == SaveStates.Saved)
{
}
However, this can be rather unintuitive to other developers - usually flag enums are not used this way. So explicitly stating all conditions with all enum values might be much more readable. Very good idea posted by Konamiman:
public static bool IsSaved(SaveStates state)
{
return state == SaveStates.SavedWithChanges
|| state == SaveStates.SavedWithoutChanges;
}
combines best of two worlds: principle of least astonishment satisfied while being concise and readable.
What about changing your enumeration?
public enum SaveStates
{
NotSaved, //Represents "not saved" state
SavedWithChanges, //Represents a successful save, where records were modified
SavedWithoutChanges //Represents a successful save, but no records were modified
}
In this case you can use negation for the purpose you're speaking of:
if (lastState != SaveStates.NotSaved)
{
//The state is saved, do something awesome.
}
Also, it gives you an enumeration value which can be used as the "default" one which is considered a good, "clean code" practice.
I would prefer this:
SaveStates[] savedWithOrWithoutChanges = { SaveStates.SavedWithChanges, SaveStates.SavedWithoutChanges };
if (savedWithOrWithoutChanges.Contains(lastStat))
{
...
}
This is very intuitive, every developer will understand it.
Instead of one enum to represent two things why not just use two bool values. One to indicate if it is saved and the other to indicate if it is "with changes". Then you'd just ignore the second if the first is false.
private bool saved;
private bool withChanges;
public void SomeMethod()
{
if (saved)
{
Console.WriteLine("Saved");
if (withChanges)
{
Console.WriteLine("With Changes");
}
else
{
Console.WriteLine("Without Changes");
}
}
else
{
Console.WriteLine("Not saved");
}
}

Getting Distinct count from the list

I am trying to find the number of unique dates in my list.
IEnumerable<T>
public int CountUniqueDate()
{
return _items.DistinctBy(i => i.DateMeasured).Count();
}
I think, this function will tell me the count of the unique dates in the list.
Now, from the other file, I try to retrieve the value
Either I want the count or the condition which will tell whether it is one or not.
So I try this to check whether the count is 1 or not.
But, here i get compilation error.
If I do var ans, then I get a full list.
List<T> li;
bool ans= li.Where(x => x.Measures.CountUniqueDate() == 1);
Can anyone please help me.
I wanna check, if the CountUniqueDate returns value 1 or not.
The WHERE CLAUSE doesnt return a boolean but an IEnumerable(Of TSource)
If you wan't to check if the there is one with count = 1 or not you might use
bool ans= li.Any(x => x.Measures.CountUniqueDate() == 1);
Change your method to be an extension method like this
public static class Extensions
{
public static int CountUniqueDate(this List<Measure> items) //<= measure is your T type
{
return items.DistinctBy(i => i.DateMeasured).Count();
}
}
then you can call it like this:
List<Measure> li = YourData;
bool ans= li.CountUniqueDate() == 1;

Explain how delegates work in the following code?

I am curious on how the following code works, especially the part the contains the delegate stuff since I am new to it. Also, are there any bottlenecks in the code, for example, would using a SortedDictionary be better than using a List and then sorting it using LINQ? Ok, here is the code:
public class ColorManager
{
private List<ColorData> colorCodes = new List<ColorData>();
public List<ColorData> ColorCodes
{
get
{
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
return sortList.ToList();
}
}
public void FillData(DataTable table)
{
for(int row = 0; row < table.Rows.Count; row++)
{
ColorData cData = new ColorData();
string name = table.Rows[row]["Color"].ToString().Trim();
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
{
cData.Add(table.Rows[row]["Color"].ToString());
this.colorCodes.Add(cData);
}
else
{
this.colorCodes.Find(
delegate(ColorData e)
{
return e.ColorCode == name;
}).Count++;
}
}
}
}
I am curious on how the following code works, especially the part the contains the delegate stuff since I am new to it.
First take a look at this ColorCodes property accessor:
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
It returns a list of all the color codes (this.colorCodes) in ascending order (...orderby a.colorCode ascending). Simple so far. How about the meatier FillData method?
First, we'll loop over every row in this table:
for(int row = 0; row < table.Rows.Count; row++)
{
Then, we're going to look at the Color column of the current row.
ColorData cData = new ColorData();
string name = table.Rows[row]["Color"].ToString().Trim();
If that column has no match in our list of color codes, this if condition is true. The Exists method takes a single-argument function that returns a bool, which is what this anonymous delegate is: a single-argument (ColorData e) function that returns a boolean (e.ColorCode == name). It gets negated (!this.[...]), so if a match is found, the condition is false.
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
{
cData.Add(table.Rows[row]["Color"].ToString());
this.colorCodes.Add(cData);
}
Otherwise, if there's a match, find the name using another anonymous delegate, and add one to the count of items of that color.
else
{
this.colorCodes.Find(
delegate(ColorData e)
{
return e.ColorCode == name;
}).Count++;
}
}
Note that this code is somewhat inefficient, since the two different anonymous delegates really do the same thing and could be shared.
Actually, there are more delegates there than you expect. The LINQ query:
var sortList = from a in this.colorCodes
orderby a.colorCode ascending
select a;
is actually:
var sortList = this.colorCodes.OrderBy(a => a.colorCode);
which (for LINQ-to-Objects) is the same as:
var sortList = this.colorCodes.OrderBy(delegate (ColorData a) {
return a.colorCode;
})
This uses a delegate to identify the item to sort by - i.e. "given a ColorData, I'll give you the colorCode". Note that many select uses also involve a delegate, but not in this case (the trivial select a is removed by the compiler).
In the code:
if(!this.colorCodes.Exists(
delegate(ColorData e)
{
return e.ColorCode == name;
}))
we are using a predicate; "given a ColorData, I'll tell you whether it is a match, by testing the name for equality". Note that name here is "captured" into the delegate, which involves some fairly complex compiler tricks (I won't describe them).
Re efficiencies; it is hard to be sure, but perhaps:
Dictionary<string, ColorData> items = new Dictionary<string, ColorData>();
foreach(DataRow row in table.Rows) {
string name = row["Color"].ToString().Trim();
ColorData cData;
if (items.TryGetValue(name, out cData)) {
cData.Count++;
} else {
cData.Add(name);
colorCodes.Add(cData);
items.Add(name, cData);
}
}
This avoids lots of duplication, and uses a dictionary to find values rather than constantly using Contains/Find. In many cases, a LINQ GroupBy might have helped, but not in this case, perhaps.
Its an anonymous delegate that serves as the selection criteria for the find expression. In words, if the color is equal to the color given by name, it will return true and Find will add this to the IEnumerable that it is generating. If it returns false, Find will not contain it. It can be written more succinctly as
p => p.ColorCode == name
Exists and Find are generic extension methods. They for for each loop over each item in the collection. Passing the delegate a parameter (defined like "(ColorData e)"), and returning a boolean.
Delegates:
The delegates in this example are implementing a Func method. Basically, what you're doing, is creating a method on the fly that takes a ColorData argument, and returns a bool.
This lets you do your Exists() and Find() calls on every member of your IEnumerable collection for checking and filtering.
As for Sorted Dictionary:
If this is the only place you're using it, you'd be better off using SortedDictionary, since you wouldn't be resorting it constantly. Right now, every time you call ColorCodes you're resorting. A SortedDictionary would be constantly sorted.

intro to lambda/anonymous functions

I have this function from a plugin (from a previous post)
// This method implements the test condition for
// finding the ResolutionInfo.
private static bool IsResolutionInfo(ImageResource res)
{
return res.ID == (int)ResourceIDs.ResolutionInfo;
}
And the line thats calling this function:
get
{
return (ResolutionInfo)m_imageResources.Find(IsResolutionInfo);
}
So basically I'd like to get rid of the calling function. It's only called twice (once in the get and the other in the set). And It could possible help me to understand inline functions in c#.
get
{
return (ResolutionInfo)m_imageResources.Find(res => res.ID == (int)ResourceIDs.ResolutionInfo);
}
Does that clear it up at all?
Just to further clear things up, looking at reflector, this is what the Find method looks like:
public T Find(Predicate<T> match)
{
if (match == null)
{
ThrowHelper.ThrowArgumentNullException(ExceptionArgument.match);
}
for (int i = 0; i < this._size; i++)
{
if (match(this._items[i]))
{
return this._items[i];
}
}
return default(T);
}
So as you can see, it loops through the collection, and for every item in the collection, it passes the item at that index to the Predicate that you passed in (through your lambda). Thus, since we're dealing with generics, it automatically knows the type you're dealing with. It'll be Type T which is whatever type that is in your collection. Makes sense?
Just to add , does the "Find" Function on a list (which is what m_imageresources is) automatically pass the parameter to the IsResoulutionInfo function?
Also, what happens first the cast or the function call?

Categories