I would like to do a custom operation on a list's members and be able to specify on which property I would perform it but I'm having a hard time finding the correct syntax for assigning the result back to the property.
Example :
I have a list of terms such as the one below and would like to normalize their 'Frequency'.
public class Term
{
public string Name { get; set; }
public double Frequency { get; set; }
public double Weight { get; set; }
}
Using some syntax like this I should be able to specify the property I am doing the operation on :
List<Term> list = Normalize(artist.Terms, s => s.Frequency);
(here it's 'Frequency' on 'Term' but I should be able to do that on any property of any type, property type will always be a double)
So that's what I crafted but I can't find out how to perform the operation nor assigning the result back to the property :
private static List<T> Normalize<T>(List<T> elements, Func<T, double> func)
{
List<T> list = new List<T>();
double fMin = elements.Min(func);
double fMax = elements.Max(func);
double fDelta = fMax - fMin;
double fInv = 1.0d / fDelta;
for (int i = 0; i < elements.Count; i++)
{
T t = elements[i];
// What should I do from here ?
//double invoke = func.Invoke(term);
//term.Frequency = (term.Frequency - fMin) * fInv;
}
return list;
}
How would you achieve this ?
If you want to avoid using expressions and reflection, you can simply provide both a getter function and a setter function. I also slightly updated the method since it would be altering the objects in original list, so I didn't think it'd be wise to create and return a new list; the API would be deceptive. (you can easily switch it back if desired)
private static void Normalize<T>(List<T> elements, Func<T, double> getter, Action<T, double> setter)
{
double fMin = elements.Min(getter);
double fMax = elements.Max(getter);
double fDelta = fMax - fMin;
double fInv = 1.0d / fDelta;
for (int i = 0; i < elements.Count; i++)
{
T t = elements[i];
double initialValue = getter(t);
double newValue = (initialValue - fMin) * fInv;
setter(t, newValue);
}
}
With usage like:
Normalize(terms, t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);
And of course it's easy to update to be an extension method so it could be used like:
terms.Normalize(t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);
With this change in the Normalize signature, it's clear you are altering the existing list and not producing a new one. With the old signature, it would appear you are leaving the old list and objects untouched which is not the case.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With