C# find object in list using a object field - c#

So i have the following List:
List<AttackStyle> AttackStyles = new List<AttackStyle>();
With the following types of objects:
AttackStyle lStyle = new AttackStyle();
lStyle.Name = "Attack Achilles";
lStyle.ParameterID = 0;
lStyle.Forward = Vector3.forward;
lStyle.HorizontalFOA = 70f;
lStyle.VerticalFOA = 40f;
lStyle.DamageModifier = 1f;
lStyle.ActionStyleAlias = "Jump";
lStyle.IsInterruptible = true;
AttackStyles.Add(lStyle);
Now i wish to find the field ParameterID where the ActionStyleAlias is equal to a value (for instance "Jump")
This is for a Unity application so the search / find needs to be as fast as possible.

var result = AttackStyles.FirstOrDefault(x => x.ActionStyleAlias == "Jump").ParameterID;

The straight solution is:
var pId = AttackStyles.FirstOrDefault(x=> x.ActionStyleAlias == "Jump")?.ParameterID
But if you want to get a better performance, it would be better, to index the most useful property which you want. Therefore, construct a dictionary on the most useful fields to get a better performance in time. For example:
var styles = new Dictionary<string, AttackStyle>();
styles.Add("Jump", new AttackStyle()
{
Name = "Attack Achilles",
ParameterID = 0,
Forward = Vector3.forward,
HorizontalFOA = 70f,
VerticalFOA = 40f,
DamageModifier = 1f,
ActionStyleAlias = "Jump",
IsInterruptible = true
});
Then, find the object by this:
var pId = styles["Jump"].ParamterId;
or if it might be null:
if(styles.Keys.Contains("Jump"))
var pId = styles["Jump"].ParamterId;

var param = AttackStyles.First(x => x.ActionStyleAlias.Equals(value)).ParameterID;

Let's return first ParameterID if there's the required item in the collection; -1 otherwise:
var result = AttackStyles
.Where(item => item.ActionStyleAlias == "Jump")
.Select(item => item.ParameterID)
.DefaultIfEmpty(-1)
.First();

You can try extension methods. Also you should consider null cases:
static class Extensions
{
public static int? FindParameterId(this List<AttackStyle> values, string actionStyleAlias)
{
return values.FirstOrDefault(x => x.ActionStyleAlias == actionStyleAlias)?.ParameterID;
}
}
Then use it:
List<AttackStyle> attackStyles = new List<AttackStyle>();
var parameterId = attackStyles.FindParameterId("Jump");

Related

Is there a way that I can set more than one property in a list to "" or null at the same time with a .ForEach?

I have this code that works but I would like to simplify it. I tried to string each .ForEach together but seems like that's not possible. Can someone suggest how I can combine these:
phraseSources
.ToList()
.ForEach(i => i.JishoExists = "");
phraseSources
.ToList()
.ForEach(i => i.CommonWord = "");
phraseSources
.ToList()
.ForEach(i => i.JishoWanikani = null);
phraseSources
.ToList()
.ForEach(i => i.JishoJlpt = null);
Because of ForEach first parameter is Action<T> which mean you can use a delegate method with one parameter.
you can try to use big parentheses on the delegate parameter.
phraseSources
.ToList()
.ForEach(i => {
i.JishoExists = "";
i.CommonWord = "";
i.JishoWanikani = null;
i.JishoJlpt = null;
});
I think that foreach (not ForEach) is the best tool for this job.
foreach(var i in phraseSources)
{
i.JishoExists = "";
i.CommonWord = "";
i.JishoWanikani = null;
i.JishoJlpt = null;
}
ToList().ForEach can lead to unexpected results. Consider the following example.
public class XClass {public string A {get; set;}}
public struct XStruct {public string A {get; set;}}
public static void Main(string[] args)
{
var array1 = new []{new XClass{A="One"}, new XClass{A="Two"}};
var array2 = new []{new XStruct{A="One"}, new XStruct{A="Two"}};
array1.ToList().ForEach( x => x.A = "XXX");
array2.ToList().ForEach( x => x.A = "XXX");
Console.WriteLine(array2[0].A); // Ooops: it's still "One"
}

Get Distinct values out of List<Object>

I have a List that contains instances of Beam class. Each of these Beam objects has an Elevation property.
List<Beam> Beams = new List<Beam> {Beam1, Beam2, ...};
public class Beam
{
public double Elevation;
}
Now I want to create a List<double> that contains distinct Elevations.
For example how to write a method that accepts the Beams list as below
var Beam1 = new Beam { Elevation = 320);
var Beam2 = new Beam { Elevation = 320);
var Beam3 = new Beam { Elevation = 640);
var Beam4 = new Beam { Elevation = 0);
List<Beam> Beams = new List<Beam> {Beam1, Beam2, Beam3, Beam4};
And gives this removing the duplicate elevations:
listOfElevations = {0, 320,640}
1) Make Beam implement IComparable:
public class Beam : IComparable
{
public double Elevation; //consider changing this to property, btw.
public int CompareTo(object obj) {
if (obj == null) return 1;
Beam otherBeam = obj as Beam;
return this.Elevation.CompareTo(otherBeam.Elevation);
}
}
2) use Distinct():
var listOfElevations = Beams.Distinct().Select(x=> x.Elevation).ToList();
Use Linq - in particular the Enumerable.Distinct() method is key here:
var listOfElevations = beams.Select(x => x.Elevation) //project to Elevations
.Distinct() // pick only distinct ones
.ToList(); //make it a list
Quite simple using LinQ:
var listOfElevations = Beams.Select(x => x.Elevation).Distinct().ToList();
You're selecting the values of Elevation, choosing the Distinct values, making it to a List since it's your expected output.
List<Beam> Beams = new List<Beam> {Beam1, Beam2, Beam3, Beam4};
var differentBeams = Beams.Select(b => b.Elevation).Distinct().ToList();
Another way using LINQ, this might be useful if you have more than one property and want to get an unique list
beams.GroupBy(x => x.Elevation).Select(g => g.Key);

Why reflection does not find property

I have the class:
class Person
{
public string Name { get { return "Antonio"; } }
}
and the Code:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>( );
var observCol = uncknownObject.GetType( );
var x = ( ( dynamic )observCol ).GenericTypeArguments[ 0 ];
var y = observCol.GetProperty( "GenericTypeArguments" );
var instance = ( Person )Activator.CreateInstance( x );
Console.WriteLine( instance.Name ); // Print Antonio!!!
why does y == null ?
Note the picture:
the debugger shows that the property GenericTypeArguments should exist and the code shows the opossite. It can be proven that the debugger is right and that property exist because then how come x is not null. If that property exists then why y is equal to null!!!???
Edit
Thanks to Ani I now have:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var genTypeArgsProperty = typeof(Type).GetProperty("UnderlyingSystemType");
var genTypeArgsValue = (genTypeArgsProperty.GetValue(observCol, null));
var f = genTypeArgsValue.GetType().GetMethod("GetGenericArguments");
IEnumerable<object> result = (IEnumerable<object>)f.Invoke(genTypeArgsValue, null);
var x = result.FirstOrDefault();
var instance = Activator.CreateInstance( (Type)x );
In case of curios why I needed that functionality click here
I don't really understand what you're trying to accomplish with all this meta-meta-reflection, but you seem to have misunderstood what Type.GetProperty does. It gets meta-data for a property on the actual type represented by the System.Type instance (in this case, ObservableCollection<Person>). It does not get meta-data for a property declared on System.Type itself, unless of course you call it on a System.Type representing System.Type itself.
In your case, y is null since ObservableCollection<Person> does not have a property named "GenericTypeArguments".
Try this instead:
var genTypeArgsProperty = typeof(Type).GetProperty("GenericTypeArguments");
var genTypeArgsValue = (Type[]) (genTypeArgsProperty.GetValue(observCol, null));
var onlyTypeArgValue = genTypeArgsValue.Single();
This code works with net framework 4:
IEnumerable<object> uncknownObject;
uncknownObject = new ObservableCollection<Person>();
var observCol = uncknownObject.GetType();
var x = ((dynamic) observCol).UnderlyingSystemType.GetGenericArguments()[0];
var y = observCol.GetGenericArguments();
var instance = (Person)Activator.CreateInstance(x);
Console.WriteLine(instance.Name); // Print Antonio!!!

Sort list by field (C#)

I have class like:
class SortNode
{
public Int32 m_valRating = 0;
public SortNode(Int32 valRating)
{
this.m_valRating = valRating;
}
}
and some list refSortNodeList:
List<SortNode> refSortNodeList = new List<SortNode>();
Random refRandom = new Random();
for (int i = 0; i < 100; ++i)
{
refSortNodeList.Add(new SortNode(refRandom.Next(-10, 30)));
}
foreach (var varSortNode in refSortNodeList)
{
Console.WriteLine("SortNode rating is {0}", varSortNode.m_valRating);
}
How to sort easily my refSortNodeList by m_valRating field? Or maybe I need to use some another List class?
list.Sort((x,y) =>
x.m_valRating.CompareTo(y.m_valRating));
In-place:
refSortNodeList.Sort(
(x, y) =>
x == null ? (y == null ? 0 : -1)
: (y == null ? 1 : x.m_valRating.CompareTo(y.m_valRating))
);
Creating a new enumeration:
var newEnum = refSortNodeList.OrderBy(x => x.m_valRating);
Creating a new list:
var newList = refSortNodeList.OrderBy(x => x.m_valRating).ToList();
In-place is fastest and most memory efficient, but no good if you want to also retain the old list.
The next is faster than the last and gives results as they go, but you have to re-do the sort to use it again, in which case the third is the one to go for.
Use Linq order by.
var mySortedList = refSortNodeList.OrderBy(x => x.m_valRating);
Here is a real live example where I am pulling a list from a database but it is exactly the same concept.
vendorProducts = (from vp in db.COMPANIES_VND_PRODUCTS
join p in db.CT_CT_INV_CLASSES on vp.CLASS_ID equals p.CLASS_ID
join m in db.CT_CT_MODALITY_CODES on vp.MODALITY_ID equals m.MODALITY_ID
where vp.COMPANY_ID == companyId
select new ProductTypeModality
{
Active = p.ACTIVE.Equals("Y") ? true : false,
BioMedImaging = p.BIOMED_IMAGING,
Code = p.CLASS_CODE,
Description = p.DESCRIPTION,
Id = p.CLASS_ID,
PricingMargin = p.PRICING_MARGIN,
ModalityCode = m.MODALITY_CODE,
ModalityId = m.MODALITY_ID,
VendorId = companyId
}).OrderBy(x => x.Code).ToList<ProductTypeModality>();
Implement IComparable<T>
You can use Linq for basic sorts:
refSortNodeList.OrderBy(n => n.m_valRating);
If you need more complex sorting your will need to implement IComparable to use the built in sorting.
Try this:
refSortNodeList.Sort(new delgate(SortNode x, SortNode y)
{
return x.CompareTo(y);
}
);
It's easy using linq:
var newlist = refSortNodeList.sort( n => n.m_valRating );
List<SortNode> refSortNodeList = new List<SortNode> ();
Random refRandom = new Random ();
for (int i = 0; i < 100; ++i) {
refSortNodeList.Add (new SortNode (refRandom.Next (-10, 30)));
}
// Use this (Linq) if you're using .NET 3.5 or above.
var sortedList = refSortNodeList.OrderBy (node => node.m_valRating);
foreach (var varSortNode in sortedList) {
Console.WriteLine ("SortNode rating is {0}", varSortNode.m_valRating);
}
// Use this otherwise (e.g. .NET 2.0)
refSortNodeList.Sort (
delegate (SortNode n1, SortNode n2) {
return n1.m_valRating.CompareTo (n2.m_valRating);
}
);
foreach (var varSortNode in refSortNodeList) {
Console.WriteLine ("SortNode rating is {0}", varSortNode.m_valRating);
}

Lambda expression with two objects

I know that this can be rewritten using a lambda expression. But I cant seem to figure it out. does anyone have an opinion on how it should be written using a lambda.
foreach (var _systemItem in _systemData)
{
foreach (var _institutionItem in _institutionData)
{
if (_systemItem.LookupValue == _institutionItem.OriginalSystemLookupValue)
{
_values.Add(new LookupValue()
{
DisplayText = _institutionItem.LookupText,
Value = _institutionItem.LookupValue
});
}
else
{
_values.Add(new LookupValue()
{
DisplayText = _systemItem.LookupText,
Value = _systemItem.LookupValue
});
}
}
}
Like this:
values.AddRange(from s in _systemData
from i in institutionData
select s.LookupValue == i.OriginalSystemLookupValue ?
new LookupValue {
DisplayText = _institutionItem.LookupText,
Value = _institutionItem.LookupValue
}
: new LookupValue {
DisplayText = _systemItem.LookupText,
Value = _systemItem.LookupValue
}
);
Is _values a List<LookupValue> which is empty to start with? If so, that look might look like this:
_values = (from x in _systemData
from y in _institutionData
let item = x.LookupValue == y.OriginalSystemLookupValue ? x : y
select new LookupValue { DisplayText = item.LookupText,
Value = item.LookupValue })
.ToList();
That assumes that _systemItem and _institutionItem are the same type. If they're unrelated types, you might want to give them a common interface that defines LookupText and LookupValue (or even a ToLookupValue method) and then cast one of the operands in the conditional operator to the interface. For example:
_values = (from x in _systemData
from y in _institutionData
let item = x.LookupValue == y.OriginalSystemLookupValue
? (ILookupSource) x : y
select item.ToLookupValue())
.ToList();
Sure, I have an opinion. I'd write it like this:
var pairs = _systemData.SelectMany(s =>
_institutionData.Select(i => new { System = s, Institution = i }));
_values.AddRange(pairs.Select(x =>
{
bool match = x.System.LookupValue == x.Insitution.OriginalSystemLookupValue;
return match ? new LookupValue(x.Institution) : new LookupValue(x.System);
}));
And move the object initializers for LookupValue into real constructors that take an Institution or System.

Categories

Resources