Skip to content

Commit c107d1a

Browse files
authored
Fixed calculation issues in FILTER and LAMBDA functions (#2186)
1 parent 326552a commit c107d1a

File tree

12 files changed

+658
-554
lines changed

12 files changed

+658
-554
lines changed

src/EPPlus/FormulaParsing/DependencyChain/LambdaInvoker.cs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ internal static CompileResult InvokeLambdaFunction(RpnOptimizedDependencyChain d
6060
}
6161
}
6262
}
63+
f.OnLambdaInvoked();
6364
return result;
6465
}
6566
}

src/EPPlus/FormulaParsing/DependencyChain/RpnFormulaExecution.cs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1179,7 +1179,6 @@ private static FormulaRangeAddress[] ExecuteNextToken(RpnOptimizedDependencyChai
11791179
CompileResult lambdaResult = LambdaInvoker.InvokeLambdaFunction(depChain, f);
11801180
if (lambdaResult != null)
11811181
PushResult(depChain._parsingContext, f, lambdaResult);
1182-
f.OnLambdaInvoked();
11831182
}
11841183
else if(f._funcStack.Count > 0)
11851184
{
@@ -1257,6 +1256,11 @@ private static FormulaRangeAddress[] ExecuteNextToken(RpnOptimizedDependencyChai
12571256
}
12581257

12591258
var r = ExecFunc(depChain, f, funcExp);
1259+
if(funcExp.ExecutesLambda)
1260+
{
1261+
// these functions will always invoke at least one LAMBDA
1262+
f.OnLambdaInvoked();
1263+
}
12601264
funcExp.OnDispose();
12611265
if (r.ResultType == CompileResultType.DynamicArray_AlwaysSetCellAsDynamic)
12621266
{

src/EPPlus/FormulaParsing/Excel/Functions/Logical/ByCol.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ internal class ByCol : ExcelFunction
2828

2929
public override string NamespacePrefix => "_xlfn.";
3030

31+
public override bool ExecutesLambda => true;
32+
3133
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
3234
{
3335
var range = ArgToRangeInfo(arguments, 0);

src/EPPlus/FormulaParsing/Excel/Functions/Logical/ByRow.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ internal class ByRow : ExcelFunction
2828

2929
public override string NamespacePrefix => "_xlfn.";
3030

31+
public override bool ExecutesLambda => true;
32+
3133
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
3234
{
3335
var range = ArgToRangeInfo(arguments, 0);

src/EPPlus/FormulaParsing/Excel/Functions/Logical/IfError.cs

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -33,8 +33,7 @@ public override void ConfigureArrayBehaviour(ArrayBehaviourConfig config)
3333
config.SetArrayParameterIndexes(0, 1);
3434
}
3535
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
36-
{
37-
36+
{
3837
var arg1 = arguments[0];
3938
var arg2 = arguments[1];
4039
if (arg1.ValueIsExcelError)

src/EPPlus/FormulaParsing/Excel/Functions/Logical/Map.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -62,6 +62,8 @@ public object GetByIndex(int index)
6262

6363
public override string NamespacePrefix => "_xlfn.";
6464

65+
public override bool ExecutesLambda => true;
66+
6567
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
6668
{
6769
var lastArg = arguments.LastOrDefault();

src/EPPlus/FormulaParsing/Excel/Functions/Logical/Reduce.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ internal class Reduce : ExcelFunction
3131

3232
public override string NamespacePrefix => "_xlfn.";
3333

34+
public override bool ExecutesLambda => true;
35+
3436
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
3537
{
3638
object initialValue = null;

src/EPPlus/FormulaParsing/Excel/Functions/Logical/Scan.cs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,8 @@ internal class Scan : ExcelFunction
2828

2929
public override string NamespacePrefix => "_xlfn.";
3030

31+
public override bool ExecutesLambda => true;
32+
3133
public override CompileResult Execute(IList<FunctionArgument> arguments, ParsingContext context)
3234
{
3335
if (arguments[0].IsExcelRange)

src/EPPlus/FormulaParsing/Excel/Functions/RefAndLookup/Filter.cs

Lines changed: 9 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ public override CompileResult Execute(IList<FunctionArgument> arguments, Parsing
5151
return CompileResult.GetErrorResult(eErrorType.Value);
5252
}
5353

54-
if(s1.NumberOfRows==s2.NumberOfRows)
54+
if(s1.NumberOfRows==s2.NumberOfRows & s1.NumberOfRows > 1)
5555
{
5656
return FilterOnRow(arg1, arg2, arg3);
5757
}
@@ -79,7 +79,7 @@ private static CompileResult FilterOnRow(IRangeInfo arg1, IRangeInfo arg2, Funct
7979
var s1 = arg1.Size;
8080
var s2 = arg2.Size;
8181

82-
if (s2.NumberOfCols != 1)
82+
if (s2.NumberOfCols != 1 && s1.NumberOfCols != s2.NumberOfCols)
8383
{
8484
return CompileResult.GetDynamicArrayResultError(eErrorType.Value);
8585
}
@@ -127,7 +127,7 @@ private static CompileResult FilterOnColumn(IRangeInfo arg1, IRangeInfo arg2, Fu
127127
var s1 = arg1.Size;
128128
var s2 = arg2.Size;
129129

130-
if (s2.NumberOfRows != 1)
130+
if (s2.NumberOfRows != 1 && s1.NumberOfRows != s2.NumberOfRows)
131131
{
132132
return CompileResult.GetDynamicArrayResultError(eErrorType.Value);
133133
}
@@ -149,13 +149,14 @@ private static CompileResult FilterOnColumn(IRangeInfo arg1, IRangeInfo arg2, Fu
149149
}
150150
if (boolValue != 0)
151151
{
152-
var row = new List<object>();
153-
154-
for (int r = 0; r < s1.NumberOfCols; r++)
152+
for (int r = 0; r < s1.NumberOfRows; r++)
155153
{
156-
row.Add(arg1.GetOffset(r, c));
154+
if (filteredData.Count <= r)
155+
{
156+
filteredData.Add(new List<object>());
157+
}
158+
filteredData[r].Add(arg1.GetOffset(r, c));
157159
}
158-
filteredData.Add(row);
159160
}
160161
}
161162
if (filteredData.Count == 0)

src/EPPlusTest/FormulaParsing/Excel/Functions/Logical/MapTests.cs

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,5 +200,23 @@ public void Map_Xleta_Attribute_IsNumber()
200200
Assert.AreEqual(false, sheet.Cells["B2"].Value); // "hello" → FALSE
201201
Assert.AreEqual(false, sheet.Cells["B3"].Value); // "" → FALSE
202202
}
203+
204+
[TestMethod]
205+
public void Map_ShouldWorkInsideOtherFunction()
206+
{
207+
using var package = new ExcelPackage();
208+
var sheet = package.Workbook.Worksheets.Add("Sheet1");
209+
210+
sheet.Cells["A1"].Value = 1;
211+
sheet.Cells["A2"].Formula = "1/0";
212+
sheet.Cells["A3"].Value = 3;
213+
214+
sheet.Cells["B1"].Formula = "IFERROR(MAP(A1:A3, _xleta.SUM), \"Error!\")";
215+
sheet.Calculate();
216+
217+
Assert.AreEqual(1d, sheet.Cells["B1"].Value);
218+
Assert.AreEqual("Error!", sheet.Cells["B2"].Value);
219+
Assert.AreEqual(3d, sheet.Cells["B3"].Value);
220+
}
203221
}
204222
}

0 commit comments

Comments
 (0)