转置多次出现
Transpose multiple occurrences
编辑:我恢复了源数据源以消除我上次屏幕截图的歧义
我正在尝试转置电子表格数据,其中有很多行客户名称可能重复,但每行包含不同的产品。
例如
revised original data source
至
revised proposed data format
如果可能的话,我想用公式来做,因为我正在努力解决 VB
感谢您的帮助
我意识到这是一个巨大的答案,抱歉,但我想说清楚。如果您需要我的任何帮助,请给我留言,我会提供帮助。
编辑后的答案 - 为便于理解而使用的命名范围:
这些只是我使用的几个命名范围的示例,您可以直接引用这些范围或自己命名它们(最简单的方法是突出显示数据,然后将名称放在旁边的下拉列表中公式栏 [左上])
请注意,由于我们将为 AccNum 和 AccType 使用数组公式,您不会希望 select 整个列,而是选择确切的数据长度或超过 100 左右。大数组公式往往会减慢计算速度,并且会单独计算每个单元格,无论它是否为空。
第一个公式
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Account Number ",LEFT((COLUMN(A:A)+1)/2,1)),"")
除了调整后的标题外,此公式与原始答案中的公式相同。
=IF(Condition,True,False)
- IF
逻辑有很多用途,在我看来它是 Excel 中最好的公式。我已经习惯用 COUNTIF
IF 来检查是否有超过 0 个单元格超过 BLANK(或 ""
)。这只是使用 ISBLANK()
或其他在出现公式时会混淆的空白标识符的技巧。
如果结果为 TRUE,我将使用 CONCATENATE(Text1,Text2,etc.)
为列 header 构建一个文本字符串。 ROW(1:1)
或 COLUMN(A:A)
通常用于启动一个自动递增的整数,供公式使用,具体取决于需要水平还是垂直增加计数。我将 1 加到这个递增的整数上并将它除以 2,这样每列的增量为 0.5 (1 > 1.5 > 2 > 2.5) 然后我使用 LEFT
公式只取左边的第一个数字十进制答案,因此数字每 2 列仅增加一次。
如果结果为假,则将单元格留空 ,"")
。标准的东西在这里,不需要解释。
第二个公式
=CONCATENATE(INDEX(Forename,MATCH(Sheet4!$A2,Reference,0)))
=CONCATENATE(INDEX(Surname,MATCH(Sheet4!$A2,Reference,0)))
CONCATENATE
仅在此处用于强制空白单元格在被 INDEX
拉动时保持空白。 INDEX
会将空白单元格读取为值,因此 0
,而 CONCATENATE
会将它们读取为文本,因此 ""
.
INDEX(Range,Row,Column)
:这是一个比 VLOOKUP
或 HLOOKUP
更高级的查找公式,并且不受它们本身的限制。
我使用的范围是预期的输出范围 - Forename
或 Surname
然后使用 MATCH(Criteria,Range,Match Type)
计算该行。匹配将查看范围和 return 匹配发生的整数位置。为此,我将条件设置为该行 A 列中的唯一参考编号,范围设置为命名范围 Reference
,匹配类型设置为 0(1 小于,0 完全匹配,-1 大于) .
我没有为 INDEX 定义列号,因为它默认为第一列,而且我只给它一列数据以供输出。
第三式
记住这些需要作为数组输入(当在公式栏中点击 Ctrl+Shift+输入)
=IFERROR(INDEX(AccNum,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0))),"")
=IFERROR(INDEX(AccType,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))),"")
如您所见,其中一个用于 AccNum
,另一个用于 AccType
。
IFERROR(Value)
:使用这个的原因是我们不期望公式总是 return 东西。当公式不能 return 某些东西或者 SMALL 有 运行 个匹配项要通过时,就会发生错误(通常是 #VALUE 或 #NUM!)所以我使用 ,"")
强制空白结果(又是标准的东西)。
我已经解释了上面的 INDEX 公式,所以让我们深入了解我是如何计算出与我们正在寻找的内容相匹配的行的:
SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))
这里的 IF 语句是不言自明的,但由于我们将其用作数组公式,它将执行 =Sheet4!$A2
,这是对命名范围 Reference
中每个单元格的唯一引用.在您的模拟数据中,这 return 是第一个条目的 {FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE}
的结果(我在范围内包含了标题,因此初始为 FALSE)。 IF
将为每个 true 进行我的行计算*,但保持 FALSE
不变。
这留下了 SMALL(array,k)
将使用的 {FALSE;2;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} 结果。 SMALL
仅适用于数值并显示第“k”个结果。再次使用列技巧,但为了覆盖更多领域,我使用了另一种方法:ROUNDDOWN(Number,digits)
而不是使用 LEFT()
这里的数字表示小数位,所以我使用 0 向下舍入为整数同样的结果。因为这会像这样跨列复制:1, 1, 2, 2, 3, 3
、SMALL
将交替地(随着公式的交替)获取第一个最小的 AccNum,然后是第一个最小的 AccType,然后再获取第二个 AcNum 和 Acctype 等等。
*(匹配的行号减去范围的第一行号,然后加 1,这也是一种相当普遍的万无一失的方法,无论数据从哪里开始,都能始终获得正确的行;实际上,当您的数据开始于第 1 行我们可以做 ROW(Reference)
但我保留原样以防你有不同格式的数据)
原始答案 - 与上述逻辑相同
您的解决方案分为 3 个部分
第 1 部分 是自动完成标题的技巧,这样它们在不使用时会隐藏(以防您只需支付并粘贴所有值即可再次加速使用)。
=IF(COUNTIF(C2:C11,">""")>0,CONCATENATE("Product ",LEFT((COLUMN(A:A)+1)/2,1)),"")
在 C
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Prod code ",LEFT((COLUMN(B:B)+1)/2,1)),"")
在 D
突出显示两个单元格并拖动以错开输出 "Product "
和 "Prod code "
第 2 部分 将向新的 sheet 输入唯一 ID,我建议复制整个 A 列跨越到一个新的 sheet 并使用 DATA > REMOVE DUPLICATES > Continue with current selection
来 trim 排除多次出现的唯一 ID。
在 B 列中使用 =INDEX(Sheet2!$B:$B,MATCH(Sheet4!$A2,Sheet2!$A:$A,0))
获取名称。
我们再次在这里进行交错输入,然后在页面上复制公式以覆盖全部数据。
=IFERROR(INDEX(Sheet2!$C:$D,SMALL(IF(Sheet2!$A:$A=Sheet4!$A2,ROW(Sheet2!$A:$A)-ROW(INDEX(Sheet2!$A:$A,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0)),1),"")
在 C
=IFERROR(INDEX(Sheet2!$C:$D,SMALL(IF(Sheet2!$A:$A=Sheet4!$A2,ROW(Sheet2!$A:$A)-ROW(INDEX(Sheet2!$A:$A,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0)),2),"")
在 D
第 3 部分的公式需要作为数组输入(当在公式栏中按 Ctrl+Shift+输入)。这需要在复制公式之前完成。
现在可以向各个方向拖动/复制这些公式,并将以 A 列中的唯一 ID 为基础。
我的答案已经很长了,所以我没有继续分解公式。如果您在理解这是如何工作时遇到任何困难,请告诉我,我很乐意编写一份快速指南,为您逐块分解。
编辑:我恢复了源数据源以消除我上次屏幕截图的歧义
我正在尝试转置电子表格数据,其中有很多行客户名称可能重复,但每行包含不同的产品。
例如 revised original data source
至
revised proposed data format
如果可能的话,我想用公式来做,因为我正在努力解决 VB
感谢您的帮助
我意识到这是一个巨大的答案,抱歉,但我想说清楚。如果您需要我的任何帮助,请给我留言,我会提供帮助。
编辑后的答案 - 为便于理解而使用的命名范围:
这些只是我使用的几个命名范围的示例,您可以直接引用这些范围或自己命名它们(最简单的方法是突出显示数据,然后将名称放在旁边的下拉列表中公式栏 [左上])
请注意,由于我们将为 AccNum 和 AccType 使用数组公式,您不会希望 select 整个列,而是选择确切的数据长度或超过 100 左右。大数组公式往往会减慢计算速度,并且会单独计算每个单元格,无论它是否为空。
第一个公式
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Account Number ",LEFT((COLUMN(A:A)+1)/2,1)),"")
除了调整后的标题外,此公式与原始答案中的公式相同。
=IF(Condition,True,False)
- IF
逻辑有很多用途,在我看来它是 Excel 中最好的公式。我已经习惯用 COUNTIF
IF 来检查是否有超过 0 个单元格超过 BLANK(或 ""
)。这只是使用 ISBLANK()
或其他在出现公式时会混淆的空白标识符的技巧。
如果结果为 TRUE,我将使用 CONCATENATE(Text1,Text2,etc.)
为列 header 构建一个文本字符串。 ROW(1:1)
或 COLUMN(A:A)
通常用于启动一个自动递增的整数,供公式使用,具体取决于需要水平还是垂直增加计数。我将 1 加到这个递增的整数上并将它除以 2,这样每列的增量为 0.5 (1 > 1.5 > 2 > 2.5) 然后我使用 LEFT
公式只取左边的第一个数字十进制答案,因此数字每 2 列仅增加一次。
如果结果为假,则将单元格留空 ,"")
。标准的东西在这里,不需要解释。
第二个公式
=CONCATENATE(INDEX(Forename,MATCH(Sheet4!$A2,Reference,0)))
=CONCATENATE(INDEX(Surname,MATCH(Sheet4!$A2,Reference,0)))
CONCATENATE
仅在此处用于强制空白单元格在被 INDEX
拉动时保持空白。 INDEX
会将空白单元格读取为值,因此 0
,而 CONCATENATE
会将它们读取为文本,因此 ""
.
INDEX(Range,Row,Column)
:这是一个比 VLOOKUP
或 HLOOKUP
更高级的查找公式,并且不受它们本身的限制。
我使用的范围是预期的输出范围 - Forename
或 Surname
然后使用 MATCH(Criteria,Range,Match Type)
计算该行。匹配将查看范围和 return 匹配发生的整数位置。为此,我将条件设置为该行 A 列中的唯一参考编号,范围设置为命名范围 Reference
,匹配类型设置为 0(1 小于,0 完全匹配,-1 大于) .
我没有为 INDEX 定义列号,因为它默认为第一列,而且我只给它一列数据以供输出。
第三式
记住这些需要作为数组输入(当在公式栏中点击 Ctrl+Shift+输入)
=IFERROR(INDEX(AccNum,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0))),"")
=IFERROR(INDEX(AccType,SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))),"")
如您所见,其中一个用于 AccNum
,另一个用于 AccType
。
IFERROR(Value)
:使用这个的原因是我们不期望公式总是 return 东西。当公式不能 return 某些东西或者 SMALL 有 运行 个匹配项要通过时,就会发生错误(通常是 #VALUE 或 #NUM!)所以我使用 ,"")
强制空白结果(又是标准的东西)。
我已经解释了上面的 INDEX 公式,所以让我们深入了解我是如何计算出与我们正在寻找的内容相匹配的行的:
SMALL(IF(Reference=Sheet4!$A2,ROW(Reference)-ROW(INDEX(Reference,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0))
这里的 IF 语句是不言自明的,但由于我们将其用作数组公式,它将执行 =Sheet4!$A2
,这是对命名范围 Reference
中每个单元格的唯一引用.在您的模拟数据中,这 return 是第一个条目的 {FALSE;TRUE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE}
的结果(我在范围内包含了标题,因此初始为 FALSE)。 IF
将为每个 true 进行我的行计算*,但保持 FALSE
不变。
这留下了 SMALL(array,k)
将使用的 {FALSE;2;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE;FALSE} 结果。 SMALL
仅适用于数值并显示第“k”个结果。再次使用列技巧,但为了覆盖更多领域,我使用了另一种方法:ROUNDDOWN(Number,digits)
而不是使用 LEFT()
这里的数字表示小数位,所以我使用 0 向下舍入为整数同样的结果。因为这会像这样跨列复制:1, 1, 2, 2, 3, 3
、SMALL
将交替地(随着公式的交替)获取第一个最小的 AccNum,然后是第一个最小的 AccType,然后再获取第二个 AcNum 和 Acctype 等等。
*(匹配的行号减去范围的第一行号,然后加 1,这也是一种相当普遍的万无一失的方法,无论数据从哪里开始,都能始终获得正确的行;实际上,当您的数据开始于第 1 行我们可以做 ROW(Reference)
但我保留原样以防你有不同格式的数据)
原始答案 - 与上述逻辑相同
您的解决方案分为 3 个部分
第 1 部分 是自动完成标题的技巧,这样它们在不使用时会隐藏(以防您只需支付并粘贴所有值即可再次加速使用)。
=IF(COUNTIF(C2:C11,">""")>0,CONCATENATE("Product ",LEFT((COLUMN(A:A)+1)/2,1)),"")
在 C
=IF(COUNTIF(D2:D11,">""")>0,CONCATENATE("Prod code ",LEFT((COLUMN(B:B)+1)/2,1)),"")
在 D
突出显示两个单元格并拖动以错开输出 "Product "
和 "Prod code "
第 2 部分 将向新的 sheet 输入唯一 ID,我建议复制整个 A 列跨越到一个新的 sheet 并使用 DATA > REMOVE DUPLICATES > Continue with current selection
来 trim 排除多次出现的唯一 ID。
在 B 列中使用 =INDEX(Sheet2!$B:$B,MATCH(Sheet4!$A2,Sheet2!$A:$A,0))
获取名称。
我们再次在这里进行交错输入,然后在页面上复制公式以覆盖全部数据。
=IFERROR(INDEX(Sheet2!$C:$D,SMALL(IF(Sheet2!$A:$A=Sheet4!$A2,ROW(Sheet2!$A:$A)-ROW(INDEX(Sheet2!$A:$A,1,1))+1),ROUNDDOWN((COLUMN(A:A)+1)/2,0)),1),"")
在 C
=IFERROR(INDEX(Sheet2!$C:$D,SMALL(IF(Sheet2!$A:$A=Sheet4!$A2,ROW(Sheet2!$A:$A)-ROW(INDEX(Sheet2!$A:$A,1,1))+1),ROUNDDOWN((COLUMN(B:B)+1)/2,0)),2),"")
在 D
第 3 部分的公式需要作为数组输入(当在公式栏中按 Ctrl+Shift+输入)。这需要在复制公式之前完成。
现在可以向各个方向拖动/复制这些公式,并将以 A 列中的唯一 ID 为基础。
我的答案已经很长了,所以我没有继续分解公式。如果您在理解这是如何工作时遇到任何困难,请告诉我,我很乐意编写一份快速指南,为您逐块分解。