数组公式成正则一

在这里输入图像说明

大家好,通过使用数组公式来计算(在上面的例子中):

只计算仅购买less于5个单位的唯一产品1的唯一客户,其中地区代码仅与相邻的D单元匹配

我使用以下数组公式在E11中:

=SUM(IF(FREQUENCY(IF($G$2:$G$7=D11, IF($I$2:$I$7="Product 1",IF($J$2:$J$7<5,IF($E$2:$E$7<>"", MATCH($E$2:$E$7,$E$2:$E$7,0))))),ROW($E$2:$E$7)-ROW(G2)+1),1)) 

这个公式做得很好,同时在通过非常庞大的包含大量行和列的数据库时,excel需要花费大约3分钟才能计算出一个单元格,

有没有什么办法将这个数组公式的转换为常规…任何帮助将被赞赏的最大…在此先感谢

抱歉回复晚了。

我创build了一个UDF,专注于多次执行计算,而无需多次运行整个范围。

 Public Function getCounts(AreaStr As Variant, AreaRng As Range, CustomerRng As Range, ProductRng As Range, SalesRng As Range, Optional ProductName As String = "Product 1", Optional lessThan As Double = 5) As Variant 'make sure AreaStr is an array If TypeOf AreaStr Is Range Then AreaStr = AreaStr.Value2 If Not IsArray(AreaStr) Then AreaStr = Array(AreaStr) ReDim Preserve AreaStr(1 To 1) End If 'shorten the range (this way you can use whole columns) If SalesRng(SalesRng.Cells.Count).Formula = "" Then Set SalesRng = SalesRng.Parent.Range(SalesRng.Cells(1), SalesRng(SalesRng.Cells.Count).End(xlUp)) 'make sure all ranges have the same size Set AreaRng = AreaRng.Resize(SalesRng.Rows.Count) Set CustomerRng = CustomerRng.Resize(SalesRng.Rows.Count) Set ProductRng = ProductRng.Resize(SalesRng.Rows.Count) 'Load values in variables to increase speed Dim SalesValues As Variant, UserValues As Variant, ProductValues As Variant SalesValues = AreaRng UserValues = CustomerRng ProductValues = ProductRng 'create temporary arrays to hold the values Dim buffer() As Variant, expList() As Variant ReDim buffer(1 To UBound(UserValues)) ReDim expList(1 To UBound(AreaStr), 1 To 1) Dim i As Long, j As Double, k As Long For i = 1 To UBound(AreaStr) expList(i, 1) = buffer Next buffer = Array(buffer, buffer) buffer(0)(1) = 0 For i = 1 To UBound(UserValues) If ProductValues(i, 1) = ProductName Then 'this customer purchased our product j = Application.IfError(Application.Match(UserValues(i, 1), buffer(0), 0), 0) If j = 0 Then 'first time this customer in this calculation j = i buffer(0)(j) = UserValues(i, 1) 'remember the customer name (to not calculate him again later) If Application.SumIfs(SalesRng, CustomerRng, UserValues(i, 1), ProductRng, ProductName) < lessThan Then buffer(1)(j) = 1 'customer got less than "lessThan" -> remember that End If End If If buffer(1)(j) = 1 Then 'check if we need to count the customer k = Application.IfError(Application.Match(SalesValues(i, 1), AreaStr, 0), 0) 'check if the area is one of the areas we are looking for If k Then expList(k, 1)(j) = 1 'it is -> set 1 for this customer/area combo End If End If Next For i = 1 To UBound(AreaStr) 'sum each area expList(i, 1) = Application.Sum(expList(i, 1)) Next getCounts = expList 'output array End Function 

我想你可以在没有我的帮助的情况下把它作为一个UDF来使用。

在你可以使用的表单中(例如)E11:E16

 =getCounts(D11:D15,G2:G7,E2:E7,I2:I7,J2:J7) 

只需selectE11:E16的范围并input公式,然后用CSE确认。

你也可以在E11上只用=getCounts(D11,$G$2:$G$7,$E$2:$E$7,$I$2:$I$7,$J$2:$J$7) ,然后复制下来。但那会很慢。

诀窍是,我们计算每个客户的集合的总和,至less买了一次。 那么我们存储1,如果它less于你的标准。 这适用于一般数组。 你正在寻找的每一个领域,也将获得自己的arrays。 在这里,我们也将1存储在同一个位置。 由于每个客户都只计算一次,多次让他无所谓。

这个公式简单的就是这样使用的:

 getCounts(AreaStr,AreaRng,CustomerRng,ProductRng,SalesRng,[ProductName],[lessThan]) 
  • AreaStr:您正在查找的地区代码。 应该是一个多个单元格的数组,以使udf值得使用它
  • AreaRng:区域名称的存储范围
  • CustomerRng:客户名称的存储范围
  • ProductRng:产品名称的存储范围
  • SalesRng:销售数量的存储范围
  • ProductName(可选):您正在查找的产品。 将被“产品1”,如果省略
  • lessThan(可选):产品总和的触发点。 将会是5,如果省略

大部分应该是自我解释,但是如果你还有什么问题的话,可以问一下)

好吧,我不确定我是否理解了所有的条件和积累,但是这里有一个我认为应该做的VBAfunction。

首先,从Excel Developer菜单打开VBA。 然后在VBA中,从插入菜单创build一个新的模块(只要让它成为Module1)。 然后将以下2个函数粘贴到VBA模块中。

 Public Function AreaUniqueCustomersLessThan(ReportAreaRange, AreaRange, ProductRange, SalesRange, CustomerRange) On Error GoTo Err1 Dim RptAreas() As Variant Dim Areas() As Variant, Products() As Variant, Sales() As Variant, Customers As Variant RptAreas = ArrayFromRange(ReportAreaRange) Areas = ArrayFromRange(AreaRange) Products = ArrayFromRange(ProductRange) Sales = ArrayFromRange(SalesRange) Customers = ArrayFromRange(CustomerRange) Dim r As Long, s As Long 'report and source rows indexes Dim mxr As Long, mxs As Long mxr = UBound(RptAreas, 1) mxs = UBound(Areas, 1) 'encode the ReportAreasList into accumulation array indexes Dim AreaCustomers() As Collection Dim i As Long, j As Long Dim colAreas As New Collection ReDim AreaCustomers(1 To mxr) For r = 1 To mxr On Error Resume Next 'Do we have the area already? j = colAreas(RptAreas(r, 1)) If Err.Number <> 0 Then 'Add a new area to the collection and array i = i + 1 colAreas.Add i, RptAreas(r, 1) Set AreaCustomers(i) = New Collection j = i End If Next r 'now scan the source rows, accumulating distinct customers ' for any ReportAreas For s = 1 To mxs 'is this row's Arera in the report Area list? i = 0 On Error Resume Next i = colAreas(Areas(s, 1)) On Error GoTo Err1 If i > 0 Then 'this is a report Area code, so check the conditions If Products(s, 1) = "Product 1" Then If Sales(s, 1) < 5 Then On Error Resume Next 'just ignore any duplicate errors AreaCustomers(i).Add Customers(s, 1), Customers(s, 1) On Error GoTo Err1 End If End If End If Next s 'finally, return to the report area codes, returning the distinct count ' of customers Dim count() As Variant ReDim count(1 To mxr, 1 To 1) For r = 1 To mxr count(r, 1) = AreaCustomers(colAreas(RptAreas(r, 1))).count Next r AreaUniqueCustomersLessThan = count ' "foo" Exit Function Err1: AreaUniqueCustomersLessThan = "%ERR(" & Str(Err.Number) & ")%" & Err.Description Exit Function Resume End Function 'handle all of the cases, checking and conversions to convert ' a variant range into an array of Variant(1 to n, 1 to 1) ' (we do this because it makes data access very fast) Function ArrayFromRange(varRange As Variant) Dim rng As Range Dim A() As Variant Set rng = varRange 'Check for degenerate cases If rng Is Nothing Then 'do nothing ElseIf rng.count = 0 Then 'do nothing ElseIf rng.count = 1 Then ReDim A(1 To 1, 1 To 1) A(1, 1) = rng.Value Else A = rng.Value End If ArrayFromRange = A End Function 

最后,进入Array Formula区域,粘贴下列“销售<5”列表中的Array公式: {=AreaUniqueCustomersLessThan(D$11:D$16, G$2:G$7, I$2:I$7,J$2:J$7,E$2:E$7)}请注意,第一个范围必须与Array Formula范围本身的长度相同。 而其他四个范围(源数据范围)应该都是相同的长度(它们不必与第一个范围的长度相同)。