[英]Perform operation on each item in a list against every other item in the list with exclusions
[英]Execute a custom operation on each item of a List<T>
我想對列表的成員進行自定義操作,並且能夠指定我將執行它的屬性,但是我很難找到將結果分配回屬性的正確語法。
示例:
我有一個術語列表,如下面的術語,並希望規范化他們的“頻率”。
public class Term
{
public string Name { get; set; }
public double Frequency { get; set; }
public double Weight { get; set; }
}
使用這樣的語法我應該能夠指定我正在進行操作的屬性:
List<Term> list = Normalize(artist.Terms, s => s.Frequency);
(這里是'Term'上的'Frequency',但我應該可以在任何類型的任何屬性上執行此操作,屬性類型將始終為double)
這就是我精心制作但我無法找到如何執行操作,也沒有將結果分配回屬性:
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;
}
你會如何實現這一目標?
如果要避免使用表達式和反射,可以簡單地同時提供getter
函數和setter
函數。 我也稍微更新了方法,因為它會改變 原始列表中的對象,所以我認為創建和返回新列表並不明智; API會具有欺騙性。 (如果需要,你可以輕松切換回來)
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);
}
}
使用方式如下:
Normalize(terms, t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);
當然,很容易更新為擴展方法,因此它可以像以下一樣使用:
terms.Normalize(t => t.Frequency, (t, normalizedFrequency) => t.Frequency = normalizedFrequency);
通過Normalize
簽名中的這一更改,很明顯您正在更改 現有列表而不是生成新列表。 使用舊簽名,看起來您將保留舊列表和未觸及的對象,但事實並非如此。
您可以使用Expression
來獲取屬性的句柄:
private static List<T> Normalize<T>(List<T> elements, Expression<Func<T, double>> func)
{
//...
var expr = (MemberExpression)func.Body;
var property = expr.Member as PropertyInfo;
if (property != null)
property.SetValue(/* element */, /* new value */);
//...
}
此外,我建議使用IEnumerable
。 這更靈活,可以隨時轉換為列表:
private static IEnumerable<T> Normalize(...)
{
foreach(...)
{
yield return ...;
}
}
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.