如何创建具有谓词函数和选择器的通用迭代器扩展方法以创建特殊的分组方法
How to Create a generic Iterator Extension Method with Predicate Function and Selector to Create a Special Grouping Method
我正在处理我们的销售部门仍在使用的陈旧过时的 4D 数据库。我已经创建了一个 ODBC 连接来读取 tables,并且一直在为我们的执行官和经理创建可视化仪表板。
为了帮助理解。典型的数据库可能有一个订单 Table 和一个订单详细信息 table。
此数据库有一个提案 Table 和一个 [订单项] Table。此外,与给定 orderDetail 相关的可能的第 3 个 child table(例如,OrderRelease),该数据库只有前面提到的单数 [Line Item] Table,并且有没有任何关系将一个 lineitem child 与 parent lineitem 相关联。 (一个 LineItem 可以有附加的 Line Item)
示例:
| ProdCode | Price | FeatureNum | LineNum | SortOrder | NoFeature |
| ProdA | 100,000 | | 1 | 0 | FALSE |
| ProdA | 0 | ProdA_SF1 | 2 | 1 | FALSE |
| ProdA | 0 | ProdA_SF2 | 3 | 1 | FALSE |
| ProdA | 5000 | ProdA_OF1 | 4 | 2 | FALSE |
现在..一个订单中可能有多个 ProductA,每个都有自己的特殊功能配置等
查看 4D 中的原始代码,应用程序将逐行执行,并在以下时间触发小计渲染:
- 订单项的 [NoFeature] 为真
- 加载了一个新的行项目记录,该记录具有不同的产品代码
- 正在评估最后一个订单项
- 订单项的 [功能编号] 为空,正在评估的订单项不是第一个订单项。
我想做的是设置一个迭代器扩展方法来处理这个自定义分组,return 主线项目的 Ienumerable,其价格设置为呈现的小计。
这是我目前的情况:
<Extension>
Public Iterator Function SpecialGrouping(Of T)(source As IEnumerable(Of T),
ByVal predicate As Func(Of T, Integer, Boolean), ByVal Selector As Func(Of IEnumerable(Of T), T)) As IEnumerable(Of T)
Dim start As Integer = 0
While start < source.Count()
Dim enumerable = source.Skip(start).TakeWhile(predicate)
start += enumerable.Count
Yield Selector(enumerable)
End While
End Function
我不知道我的通用扩展方法实现有什么问题。我想这样称呼它:
Dim lineItems = GetLineItemsMethod ''for simplicity's sake
Dim subTotalRenderedMainItems = lineItems.SpecialGrouping(
Function(x, index) Not (x.NoFeatures OrElse (x.LineNum <> 1 AndAlso x.FeatureNum = Nothing) OrElse index = 0),
Function(x)
Dim MainItem = x.OrderBy(Function(y) y.LineNum).FirstOrDefault
MainItem.Price = x.Sum(Function(y) y.Price)
Return MainItem
End Function)
我们将不胜感激!!
您的方法非常复杂,因为它在评估期间重新开始重新枚举源。我会选择一种方法,您可以使用简单的 For Each
.
进行迭代
<Extension>
Public Iterator Function SpecialGrouping(Of T)(
source As IEnumerable(Of T),
isNewMainItem As Func(Of T, T, Boolean),
initializeMainItem As Action(Of T), 'E.g. set price to 0.0
aggregate As Action(Of T, T) 'E.g. add price of subitem (2nd param) to main item (1st param)
) As IEnumerable(Of T)
Dim currentMainItem As T = Nothing
For Each x As T In source
If isNewMainItem(currentMainItem, x) Then
If currentMainItem IsNot Nothing Then
Yield currentMainItem
End If
currentMainItem = x
initializeMainItem(currentMainItem)
ElseIf currentMainItem IsNot Nothing Then
aggregate(currentMainItem, x)
End If
Next
If currentMainItem IsNot Nothing Then
Yield currentMainItem
End If
End Function
该方法采用以下参数:
source
T
的枚举
isNewMainItem
函数委托在新组开始时返回 True
。第一个参数是当前的主项,第二个是被枚举的项。这样可以比较两者的产品代码。
initializeMainItem
。要对价格求和,必须将总和,即主项的Price
初始化为0.
aggregate
主项与副项相结合
例子
Dim lineItems = GetLineItemsMethod()
Dim subTotalRenderedMainItems = lineItems.SpecialGrouping(
isNewMainItem:=Function(main, x) main Is Nothing OrElse main.ProdCode <> x.ProdCode _
OrElse x.LineNum = 1,
initializeMainItem:=Sub(x) x.Price = 0.0,
aggregate:=Sub(main, x) main.Price = main.Price + x.Price
)
在第一次迭代期间 main
是 Nothing
。因此我们可以测试它而不是测试 index=0。您可能需要微调 isNewMainItem
.
中的条件
如果某些项目不需要汇总,那么相应的逻辑将进入aggregate
委托。例如:
aggregate:=Sub(main, x) main.Price = main.Price + If(x.NoFeatures, 0, x.Price)
我正在处理我们的销售部门仍在使用的陈旧过时的 4D 数据库。我已经创建了一个 ODBC 连接来读取 tables,并且一直在为我们的执行官和经理创建可视化仪表板。
为了帮助理解。典型的数据库可能有一个订单 Table 和一个订单详细信息 table。
此数据库有一个提案 Table 和一个 [订单项] Table。此外,与给定 orderDetail 相关的可能的第 3 个 child table(例如,OrderRelease),该数据库只有前面提到的单数 [Line Item] Table,并且有没有任何关系将一个 lineitem child 与 parent lineitem 相关联。 (一个 LineItem 可以有附加的 Line Item)
示例:
| ProdCode | Price | FeatureNum | LineNum | SortOrder | NoFeature |
| ProdA | 100,000 | | 1 | 0 | FALSE |
| ProdA | 0 | ProdA_SF1 | 2 | 1 | FALSE |
| ProdA | 0 | ProdA_SF2 | 3 | 1 | FALSE |
| ProdA | 5000 | ProdA_OF1 | 4 | 2 | FALSE |
现在..一个订单中可能有多个 ProductA,每个都有自己的特殊功能配置等
查看 4D 中的原始代码,应用程序将逐行执行,并在以下时间触发小计渲染:
- 订单项的 [NoFeature] 为真
- 加载了一个新的行项目记录,该记录具有不同的产品代码
- 正在评估最后一个订单项
- 订单项的 [功能编号] 为空,正在评估的订单项不是第一个订单项。
我想做的是设置一个迭代器扩展方法来处理这个自定义分组,return 主线项目的 Ienumerable,其价格设置为呈现的小计。
这是我目前的情况:
<Extension>
Public Iterator Function SpecialGrouping(Of T)(source As IEnumerable(Of T),
ByVal predicate As Func(Of T, Integer, Boolean), ByVal Selector As Func(Of IEnumerable(Of T), T)) As IEnumerable(Of T)
Dim start As Integer = 0
While start < source.Count()
Dim enumerable = source.Skip(start).TakeWhile(predicate)
start += enumerable.Count
Yield Selector(enumerable)
End While
End Function
我不知道我的通用扩展方法实现有什么问题。我想这样称呼它:
Dim lineItems = GetLineItemsMethod ''for simplicity's sake
Dim subTotalRenderedMainItems = lineItems.SpecialGrouping(
Function(x, index) Not (x.NoFeatures OrElse (x.LineNum <> 1 AndAlso x.FeatureNum = Nothing) OrElse index = 0),
Function(x)
Dim MainItem = x.OrderBy(Function(y) y.LineNum).FirstOrDefault
MainItem.Price = x.Sum(Function(y) y.Price)
Return MainItem
End Function)
我们将不胜感激!!
您的方法非常复杂,因为它在评估期间重新开始重新枚举源。我会选择一种方法,您可以使用简单的 For Each
.
<Extension>
Public Iterator Function SpecialGrouping(Of T)(
source As IEnumerable(Of T),
isNewMainItem As Func(Of T, T, Boolean),
initializeMainItem As Action(Of T), 'E.g. set price to 0.0
aggregate As Action(Of T, T) 'E.g. add price of subitem (2nd param) to main item (1st param)
) As IEnumerable(Of T)
Dim currentMainItem As T = Nothing
For Each x As T In source
If isNewMainItem(currentMainItem, x) Then
If currentMainItem IsNot Nothing Then
Yield currentMainItem
End If
currentMainItem = x
initializeMainItem(currentMainItem)
ElseIf currentMainItem IsNot Nothing Then
aggregate(currentMainItem, x)
End If
Next
If currentMainItem IsNot Nothing Then
Yield currentMainItem
End If
End Function
该方法采用以下参数:
source
T
的枚举
isNewMainItem
函数委托在新组开始时返回True
。第一个参数是当前的主项,第二个是被枚举的项。这样可以比较两者的产品代码。initializeMainItem
。要对价格求和,必须将总和,即主项的Price
初始化为0.aggregate
主项与副项相结合
例子
Dim lineItems = GetLineItemsMethod()
Dim subTotalRenderedMainItems = lineItems.SpecialGrouping(
isNewMainItem:=Function(main, x) main Is Nothing OrElse main.ProdCode <> x.ProdCode _
OrElse x.LineNum = 1,
initializeMainItem:=Sub(x) x.Price = 0.0,
aggregate:=Sub(main, x) main.Price = main.Price + x.Price
)
在第一次迭代期间 main
是 Nothing
。因此我们可以测试它而不是测试 index=0。您可能需要微调 isNewMainItem
.
如果某些项目不需要汇总,那么相应的逻辑将进入aggregate
委托。例如:
aggregate:=Sub(main, x) main.Price = main.Price + If(x.NoFeatures, 0, x.Price)