【发布时间】:2020-01-08 11:43:51
【问题描述】:
我正在尝试使用命令式风格的 Linq,但我无法将 Aggregate 中的这个条件转换为 Linq。
考虑以下两个示例。
简单示例:
public enum Color {
Red, // Red score = 10
Yellow, // Yellow score = 5
Green, // Green score = 2
}
//Populate our sample list
public List<Color> Colors = new List<Color> {Red, Green, Green, Yellow};
//I need help on this one
public float Score => Colors.Aggregate(0.0f, (total, next) =>
{
//How to properly use conditional inside Aggregate?
if (next == Color.Red) {
return total + 10.0f;
} else if (next == Color.Yellow) {
return total + 5.0f;
} else if (next == Color.Green) {
return total + 2.0f;
}
//edit: forgot the default
return total;
}
Log(Score); //19
编辑:我尝试将条件移动到 Select,但它只会移动问题,这是如何在 Linq Select 中添加条件?
public float Score => Colors.Select(x =>
{
// The problem still happening
if (x == Color.Red) {
return 10.0f;
} else if (x == Color.Yellow) {
return 5.0f;
} else if (x == Color.Green) {
return 2.0f;
}
return 0.0f;
}
.Aggregate(0.0f, (total, next) => total + next);
这里是复杂的例子,基本上它只是一个游戏的属性修饰符,
// This is a Game Status Modifier, for example: "Strength 30 + 10%"
public enum StatModType
{
Flat = 100, // Flat addition to Stat
PercentAdd = 200, // Percent addition to Stat
... // many other type of addition
}
private float _baseValue = 30.0f;
public List<StatModifier> StatModifiers = new List<StatModifier>
{...} //dummy data
public float Value => StatModifiers.Aggregate(_baseValue, (finalValue, mod) =>
{
//I need help on this one
if (mod.Type == StatModType.Flat)
return finalValue + mod.Value;
else if (mod.Type == StatModType.PercentAdd)
// When we encounter a "PercentAdd" modifier
return finalValue + finalValue * mod.Value;
else if (mod.Type == ...)
//and continues below everytime I add more modifier types..
}
Log(Value); // Strength = 33;
编辑:我将发布(信用:https://forum.unity.com/threads/tutorial-character-stats-aka-attributes-system.504095/)命令式代码以防有人需要它,我也很难阅读这个:
private float CalculateFinalValue()
{
float finalValue = BaseValue;
float sumPercentAdd = 0; // This will hold the sum of our "PercentAdd" modifiers
for (int i = 0; i < statModifiers.Count; i++)
{
StatModifier mod = statModifiers[i];
if (mod.Type == StatModType.Flat)
{
finalValue += mod.Value;
}
else if (mod.Type == StatModType.PercentAdd) // When we encounter a "PercentAdd" modifier
{
sumPercentAdd += mod.Value; // Start adding together all modifiers of this type
// If we're at the end of the list OR the next modifer isn't of this type
if (i + 1 >= statModifiers.Count || statModifiers[i + 1].Type != StatModType.PercentAdd)
{
finalValue *= 1 + sumPercentAdd; // Multiply the sum with the "finalValue", like we do for "PercentMult" modifiers
sumPercentAdd = 0; // Reset the sum back to 0
}
}
else if (mod.Type == StatModType.PercentMult) // Percent renamed to PercentMult
{
finalValue *= 1 + mod.Value;
}
}
return (float)Math.Round(finalValue, 4);
}
如何在 Aggregate / Reduce / Scan 函数中添加条件?
【问题讨论】:
-
过滤的方法是
Where,而不是Aggregate。如果要生成不同的值,即项目,请使用Select。Aggregate用于聚合数据,而不是做其他操作员的工作 -
聚合为所有记录生成一个值,它不能跳过或过滤它们。对于它不喜欢的任何值,它必须返回未修改的累加器值。
-
您好,我应该在使用
Aggregate之前将if..else 问题移至Select吗?将提出另一个问题,如何在Select中添加条件。我不能使用Where,因为需要所有数据。 -
如果可以的话。但是,如果您需要对不同的记录应用不同的操作,a) 您有一个很奇怪的实现,容易受到订单更改的影响;b) 您应该返回累加器,即
finalValue,未修改的return finalValue;。切换Flat和PercentAdd的顺序会得到不同的结果 -
你只需要默认返回不变的累加器。 (最后一个 else 情况)