索引多个列并匹配不同的值,返回列之间的唯一值列表
为了解决我的问题,我已经search了很长时间,现在已经过了好几个星期了。 我已经提出了一个部分工作的解决scheme,我将在底部列出那些可能知道如何修改/扩展它们以解决问题的scheme。
这是我想要完成的(下面的描述是参考这个屏幕截图http://imgur.com/oTkbjrw ):
1)我正在寻找匹配列G与列A($ G2与$ A $ 2:$ A $ 10)的值。
2)如果值匹配,则从相邻的列B,C和D中提取唯一值(不包括空格),然后跨列(H到M)返回它们。
因此,如'期望结果1'表格(G1:M10)所示,如果在A2:A10中findG2(温哥华),则从温哥华匹配的列B,C和D中提取索引值蓝色,绿色,绿色,红色,黄色,蓝绿色,绿色,粉红色,粉红色,粉红色,并且仅返回列H到L(蓝色,绿色,红色,黄色,鸭,粉红色)。
我一直在寻找一个公式解决scheme,可以popup到H2,然后水平拖到M2,揭示结果。 但是,我没有结婚这个解决scheme。 我也考虑过的另一种方法是以逗号分隔格式而不是跨列返回唯一值(请参阅'所需的结果2')。 如果这更容易完成,我完全赞成。
注意:我将在10,000行以上运行这个公式。 如果可能的话,精益/高效的解决scheme是可取的。
部分解决scheme,我一起放在一起:
1){数组公式1},结果可以在这里看到:
=IFERROR(INDEX($B$2:$B$10, SMALL(IF(COUNTIF($G2,$A$2:$A$10), MATCH(ROW($B$2:$B$10), ROW($B$2:$B$10)), ""), COLUMN(A1))),"")
此公式只能够对列B进行索引,但是它能够成功匹配并在列之间返回值。 不幸的是,它不提取唯一的值并返回空白单元格。
2)回复:贾斯汀关于一个可能的VBA解决scheme的评论,我应该popup我遇到的一个VBA解决scheme。
Function UNIQUE_PH(Lookupvalue As String, LookupRange As Range, ColumnNumber As Integer) Dim i As Long Dim Result As String For i = 1 To LookupRange.Columns(1).Cells.Count If LookupRange.Cells(i, 1) = Lookupvalue Then For J = 1 To i - 1 If LookupRange.Cells(J, 1) = Lookupvalue Then If LookupRange.Cells(J, ColumnNumber) = LookupRange.Cells(i, ColumnNumber) Then GoTo Skip End If End If Next J Result = Result & " " & LookupRange.Cells(i, ColumnNumber) & "," Skip: End If Next i UNIQUE_PH = Left(Result, Len(Result) - 1) End Function 'It takes 3 arguments as inputs: '1. Lookupvalue – A string that we need to look-up in a range of cells. '2. LookupRange – An array of cells from where we need to fetch the data '3. ColumnNumber – It is the column number of the table/array from which matching value is to be returned (eg 2 for second column).
这基本上做了上面的公式完成,除了它成功地识别唯一的值。 它以逗号分隔的方式在一个单元格中显示结果(类似于“期望的结果2”)。 这是不能够search多个列,并不会删除空白单元格。 我也试图在10,000行数据上运行它,速度很慢。 我对VBA知之甚less,所以我不确定可能会造成什么后果。
示例数据解决scheme
'in G2 =A2 'in H2 as an array formula with CSE =IFERROR(INDEX($B$2:$B$16, MATCH(0, IF($A$2:$A$16=$G2, IF(SIGN(LEN($B$2:$B$16)), COUNTIF($G2:G2, $B$2:$B$16), 1), 1), 0), 1), IFERROR(INDEX($C$2:$C$16, MATCH(0, IF($A$2:$A$16=$G2, IF(SIGN(LEN($C$2:$C$16)), COUNTIF($G2:G2, $C$2:$C$16), 1), 1), 0), 1), IFERROR(INDEX($D$2:$D$16, MATCH(0, IF($A$2:$A$16=$G2, IF(SIGN(LEN($D$2:$D$16)), COUNTIF($G2:G2, $D$2:$D$16), 1), 1), 0), 1), TEXT(,)))) 'in G19 =G2 'in H19 =TEXTJOIN(",", TRUE, H2:N2)
正确填入H2,然后按照G2:N2向下填充。 填写G19:H19以整理上面的值。 如果您获得#NAME!
请参阅脚注¹ #NAME!
TEXTJOIN函数错误。
10K行数据解决scheme
数组公式以指数forms咀嚼计算,参考范围增大。 将其作为数组公式的唯一方法是仅在为温哥华创build唯一列表时引用温哥华的行,并且只在为西雅图创build唯一列表时引用与西雅图的行。 换句话说,当温哥华的数据在第2:6行时,不要在温哥华引用第2:10000行。
注意:您将不得不将数据按列Asorting为主键。 这个操作需要它。 未分类的数据(甚至分组)将不允许第二个MATCHfunctionfind终止行。
列A中包含温哥华的列B中的数据行可以用这个引用。
INDEX(B:B, MATCH("vancouver", A:A, 0)):INDEX(B:B, MATCH("vancouver", A:A))
现在你所要做的就是把所有出现的$B$2:$B$16
换成上面的那个。 调整公式并进行$C$2:$C$16
和$D$2:$D$16
的replace。 奖金是,你可以摆脱检查,看IF($A$2:$A$16=$G2, ...
因为根据定义,你只是引用与列A中适当的城市行。确保你参考G2,不要在温哥华硬编码。
'in H2 as an array formula with CSE =IFERROR(INDEX(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A))), 1), 0)), TEXT(,))))
您应该能够在该数组公式上计算时间,即使通过10K行。
我敢肯定,这是本地工作表函数可以去。 进一步的改进将使用不同的存储器arrays。
Addendum²
还有一个进一步的优化。 工作表IF
只处理公式的部分是真实的。 如果您查看城市名称,并且只在城市名称更改时处理公式的数组部分,则在相同时从上面直接复制,则应该可以进一步限制计算。
'in H2 as an array formula with CSE =IF($G2=$G1, H1, IFERROR(INDEX(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A))), 1), 0)), TEXT(,)))))
Addendum³
单个城市的条目出现了问题,这个修正案照顾到了这个问题。
您可能会收到一个循环参考警告。 从技术上讲,这个警告是真实的,但由于嵌套的IF结构,你实际上从来没有真正得到循环引用。 换句话说,循环引用只有在IF为假时才有效。 Excel报告这个,因为它不检查条件; 只有技术上是真实的,但实际上永远不会发生循环引用的可能性。
'in H2 as an array formula with CSE =IF($G2=$G1, H1, IF(COUNTIF($A:$A, $G2)=1, IFERROR(INDEX(INDEX($B:$D, MATCH($G2, $A:$A, 0), 0), MATCH(0, IF(INDEX($B:$D, MATCH($G2, $A:$A, 0), 0)<>"", COUNTIF($G2:G2, INDEX($B:$D, MATCH($G2, $A:$A, 0), 0)), 1), 0)), TEXT(,)), IFERROR(INDEX(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($B:$B, MATCH($G2, $A:$A, 0)):INDEX($B:$B, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($C:$C, MATCH($G2, $A:$A, 0)):INDEX($C:$C, MATCH($G2, $A:$A))), 1), 0)), IFERROR(INDEX(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)), MATCH(0, IF(SIGN(LEN(INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A)))), COUNTIF($G2:G2, INDEX($D:$D, MATCH($G2, $A:$A, 0)):INDEX($D:$D, MATCH($G2, $A:$A))), 1), 0)), TEXT(,))))))
¹ 如果您的Excel版本不支持TEXTJOINfunction ,请在此网站中search[excel] [textjoin],以查找碎片长度,分隔string连接的替代方法。
试试这个UDF
Function UniquePh(Lookupvalue As String, LookupRange As Range, ValueRng As Range) As String Dim dict As Object Dim lkpArr() As Variant Dim ValArr() As Variant Set LookupRange = Intersect(LookupRange, LookupRange.Parent.UsedRange) Set ValueRng = Intersect(ValueRng, ValueRng.Parent.UsedRange) If LookupRange.Rows.Count <> ValueRng.Rows.Count Or LookupRange.Columns.Count > 1 Then Exit Function Set dict = CreateObject("Scripting.Dictionary") lkpArr = LookupRange.Value ValArr = ValueRng.Value For i = LBound(lkpArr, 1) To UBound(lkpArr, 1) If lkpArr(i, 1) = Lookupvalue Then For j = LBound(ValArr, 2) To UBound(ValArr, 2) If ValArr(i, j) <> "" Then On Error Resume Next dict.Add ValArr(i, j), ValArr(i, j) On Error GoTo 0 End If Next j End If Next i For Each itm In dict UniquePh = UniquePh & itm & ", " Next itm If Len(UniquePh) > 0 Then UniquePh = Left(UniquePh, Len(UniquePh) - 2) Else: UniquePh = "" End If End Function
把它放在工作簿附带的模块中。 然后从表单中调用它。 把这个公式放在H2中:
=UniquePh(G2,$A$2:$A$10,$B$2:$D$10)
它应该运行得更快。