索引多个列并匹配不同的值,返回列

时间:2017-03-30 21:21:54

标签: excel list excel-vba excel-formula unique vba

我已经远远地搜索了我的问题的解决方案......现在已经过了好几个星期了。我已经提出了一个部分工作的解决方案,我将在底部包含那些可能知道如何修改/扩展它们以解决问题的人。

以下是我要完成的内容(以下说明参考了此屏幕截图http://imgur.com/oTkbjrw):

enter image description here

1)我希望将G列和A列的值相匹配($ G2,$ A $ 2:$ A $ 10)。

2)如果值匹配,则从相邻的列B,C和D中提取唯一值(不包括空白),并将它们跨列(H到M)返回。

因此,如'期望结果1'表(G1:M10)所示,如果在A2:A10中找到G2(温哥华),则从列B,C和D中提取索引值,其中温哥华是匹配的(即蓝色,绿色,绿色,红色,黄色,蓝绿色,绿色,,,粉红色,粉红色,粉红色,)并且只返回H到L列的唯一值(不包括空白)(蓝色,绿色,红色) ,黄色,青色,红色)。

我一直在寻找可以弹出到H2然后水平拖动到M2的公式解决方案,以显示结果。但是,我并没有嫁给这个解决方案。我还考虑过的一种替代方法是以逗号分隔格式而不是跨列返回唯一值(请参阅“所需结果2”)。如果这更容易实现,我会全力以赴。

注意:我将在10,000多行上运行此公式。如果可能,需要精益/高效的解决方案。

我将部分解决方案放在一起:

1){数组公式1},结果可见here

=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)Re:Justin对可能的VBA解决方案的评论,我想应该弹出我遇到的一个VBA解决方案。

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 (e.g. 2 for second column).

这基本上完成了上述公式所做的事情,但它成功识别了唯一值。它将结果显示在一个单元格中以逗号分隔(类似于“所需结果2”)。这不能搜索多个列,也不能删除空白单元格。我还尝试在10,000行数据上运行它,这非常慢。我对VBA知之甚少,所以我不确定是什么原因造成了延迟。

2 个答案:

答案 0 :(得分:3)

示例数据解决方案

'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以整理上述值。如果TEXTJOIN function上出现#NAME!错误,请参阅脚注¹。

enter image description here

10K行数据解决方案

数组公式以指数方式咀嚼计算参​​考范围的大小增加。作为数组公式执行此操作的唯一方法是,在为 Vancouver 创建唯一列表时仅使用 Vancouver 引用行,并仅使用引用行您为 Seattle 创建唯一列表时的西雅图。换句话说,当温哥华的数据在行2:6中时,不要引用温哥华的第2行:10000。

  

注意:您将 以A列作为主键对数据进行排序。此操作需要它。未排序的数据(甚至是分组的)将不允许第二个MATCH函数定位终止行。

A列中包含Vancouver的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进行替换。奖励是您可以删除检查以查看IF($A$2:$A$16=$G2, ...,因为根据定义,您只在A列中引用具有相应城市的行。确保您引用G2并且不在 Vancouver < / em>的

'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行,您也应该能够使用该数组公式的计算时间。

enter image description here

我很确定这就像本机工作表函数一样。进一步的改进将是使用变体存储器阵列。

<强>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版本不支持TEXTJOIN function,请在此网站上搜索[excel][textjoin]以查找衣衫褴褛,分隔的字符串连接的备选方案。

答案 1 :(得分:1)

试试这个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)

enter image description here

它应该运行得更快。