我想聚合、合并、压缩一些值,如下所示
输入是一个表,输出是单个单元格上的动态数组公式,目标是根据第一列的唯一值聚合其他列
我的输入是一个表格(名为TAB)
姓名 | 服务 | 类型 |
---|---|---|
02HPP002NZ | 1:基本 | unix |
02HPP002NZ | 1:基本 | unix |
02HPP002NZ | 3. 相关 | 赢 |
02HPP009O4 | 3. 相关 | nt |
02HPP001L7 | 2:标准 | unix |
02HPP001L7 | 2:标准 | Linux的 |
02HPP009O4 | 1:基本 | nt |
在单个单元格 E2 上使用数组公式实现所需输出
姓名 | 服务 | 类型 |
---|---|---|
02HPP002NZ | 1:基础 / 3:相关 | Unix / WIN |
02HPP009O4 | 3:相关 / 1:基础 | nt |
02HPP001L7 | 2:标准 | unix / linux |
我使用的公式如下:
=LET(
Names; TAB[Name];
uNames; UNIQUE(Names);
aggfunc; LAMBDA(colIdx; MAP(uNames; LAMBDA(x; BYCOL(CHOOSECOLS(TAB;colIdx); LAMBDA(col;TEXTJOIN(" / "; TRUE; UNIQUE(FILTER(col; Names=x))))))));
HSTACK(
uNames;
aggfunc(2);
aggfunc(3)
)
)
正如您所注意到的,我硬编码了“aggfunc(x)”(x 是我要返回的表格的列号)。我想使用单个函数aggfunc(numCols)
,numCols是列数的数组。公式应该如下所示,但不幸的是它不起作用。它给出错误“ #CALC! ”
=LET(
Names; TAB[Name];
uNames; UNIQUE(Names);
numCols; SEQUENCE(COLUMNS(TAB[#Data]));
aggfunc; LAMBDA(colIdx; MAP(uNames; LAMBDA(x; BYCOL(CHOOSECOLS(TAB;colIdx); LAMBDA(col;TEXTJOIN(" / "; TRUE; UNIQUE(FILTER(col; Names=x))))))));
HSTACK(
uNames;
aggfunc(numCols)
)
)
使用 BYROW 代替 MAP 的替代公式
=LET(
a; TAB[Name];
b; TAB[Type];
c; TAB[Service];
ua; UNIQUE(a);
HSTACK(
ua;
BYROW(ua; LAMBDA(x; TEXTJOIN(" / ";TRUE;UNIQUE(FILTER(b;a=x)))));
BYROW(ua; LAMBDA(x; TEXTJOIN(" / ";TRUE;UNIQUE(FILTER(c;a=x)))))
)
)
我也尝试过使用 PowerQuery,但使用 group by 然后添加自定义列,但由于我有多个列,因此实现我的目标非常痛苦。如果有人可能感兴趣,请按照以下步骤操作:
- 选择表格中的任意单元格
- 选择菜单数据,然后从表/范围(在左侧)
- 它打开PowerQuery 编辑器,您现在需要选择列
Name
(第一列) - 在菜单Transform中,选择Group By。打开一个新窗口,我填写了如下所示的字段
- 新列名:
AGGNAME
- 手术:
All Rows
- 单击“确定”
- 现在您有一张包含两列的表格,标题分别为名称和 AGGNAME(表格)
- 在菜单“添加列”中,选择“自定义列”。打开一个新窗口,我输入以下值
- 新列名:
Type
- 自定义列公式:
=Text.Combine(List.Transform(List.Distinct([AGGNAME][#"Type"]), Text.From), " / ")
- 您现在有 3 列“名称”、“AGGNAME”和“类型”。
- 您需要重复步骤 6 并
Type
根据您的列的名称更改名称(在公式中)。 - 插入所有需要的新列后,必须删除AGGNAME列
- 现在转到菜单主页并单击“关闭并加载”。它将创建一个具有与我需要相同的输出的新表。
如果输入表的名称发生变化或者表有多个列,使用 PowerQuery 就会变得很痛苦。
我的 Office 365 版本尚不包含功能“GROUPBY” (版本 2406 内部版本 16.0.17726.20206) 64 位。
非常感谢您抽出时间,如果您需要更多信息,请随时询问。问候,T。
6 个回答
6
已经有很多不错的答案了。另一种方法是使用 MAKERRAY:
=LET(uNames,UNIQUE(Table1[Name]),
MAKEARRAY(ROWS(uNames),COLUMNS(Table1),
LAMBDA(rw,cl,
ARRAYTOTEXT(UNIQUE(FILTER(INDEX(Table1,,cl),Table1[Name]=INDEX(uNames,rw)))))))
PS 我使用了表格。请将其更改为 TAB 以供参考。我无法使用 Excel 的应用程序版本重命名表格名称
此外,如果您希望将分隔符更改为/
ARRAYTOTEXT 以 TEXTJOIN。
5
-
1我按照你的建议将ARRAYTOTEXT更改为TEXTJOIN,并且它也运行良好,谢谢@Pb 🙂
– -
谢谢。我在评论中看到你想使用命名的 lambda 并能够输入列索引号作为参数。你可以轻松采用这一点并使用 CHOOSECOLS
– -
1是的,我目前正在努力使其更加灵活。就我个人而言,在所有回复中,您的公式是最清晰、最直接的。谢谢
– -
谢谢(除了 GROUPBY,它目前还不可用)
– -
1很好地使用了 MAKEARRAY @Pb!
–
|
尝试这个公式:
=LET(
n,Tab[Name],nUnique,UNIQUE(n),
agg, LAMBDA(colIdx,n_,TEXTJOIN("/",TRUE,UNIQUE(FILTER(CHOOSECOLS(Tab,colIdx),n=n_)))),
DROP(
REDUCE("",nUnique,LAMBDA(r,n_,VSTACK(r,HSTACK(n_,agg(2,n_),agg(3,n_)))))
,1)
)
3
-
谢谢@ike,你的公式和我的很相似。我尝试在输入表中添加一个新列,但不幸的是,新列没有作为输出出现。我的意思是,使用我的公式,我必须手动添加“aggfunc(4)”,而使用你的公式,则添加“;agg(4;n_)”
– -
是的,你必须添加
;add(4;n_)
– -
很抱歉,我拒绝了您的建议,因为它不符合我的目标。公式应该动态返回所有输入列,而不是手动硬编码,因为表格可能包含更多列。感谢您的时间。
–
|
检索唯一过滤列
- 结果与 OP 相同,另外
Names
在左侧增加了一个额外的唯一()列,即,如果目标是堆叠所有列,则不再需要堆叠唯一的列。 - 第一行包含参数,然后是两个辅助函数和唯一名称。最后,您的聚合函数接受单个参数,期望返回列的数组。
掉进兔子洞
=LET(data,TAB,uniques,TAB[Name],cols,SEQUENCE(COLUMNS(data)),delim," / ",
GetCell,LAMBDA(cdata,cfilter,delim,BYCOL(cdata,LAMBDA(c,
TEXTJOIN(delim,,UNIQUE(FILTER(c,cfilter)))))),
GetCol,LAMBDA(data,udata,cdata,delim,
MAP(udata,LAMBDA(m,GetCell(cdata,data=m,delim)))),
u,UNIQUE(uniques),
aggfunc,LAMBDA(cols,DROP(REDUCE("",cols,LAMBDA(cc,c,
HSTACK(cc,GetCol(uniques,u,CHOOSECOLS(data,c),delim)))),,1)),
HSTACK(u,aggfunc(cols)))
2
-
谢谢@VBasic2008,我稍微修改了你的代码
cols;SEQUENCE(COLUMNS(data)-1;;2)
以避免第一列重复两次,它按预期工作。谢谢
–
-
您可以通过保留原序列并使用
aggfunc(cols))
而不是最后一行来实现相同的效果。
–
|
看起来您可以使用:
公式E2
:
=GROUPBY(A2:A8,B2:C8,LAMBDA(x,TEXTJOIN(" / ",,UNIQUE(x))),,0)
注意服务和类型是如何分组的。
3
-
1你好@JvdV,我忘了说,很遗憾我当前的 Office 365 版本尚未包含此功能(版本 2406 Build 16.0.17726.20206)64 位。我来这里就是为了创建一个新的。感谢您的时间 🙂
– -
1您昨天在 Excel BI 上发布了一个使用 的
ARRAYTOTEXT
ETA
。您知道为什么它不起作用吗?我有这个GROUPBY
功能(这个功能有效),我在 Insider 频道,我有最新的更新。
–
-
很可能 eta 尚未在当前频道 @VBasic2008 上推出。如果您在实际的 LAMBDA 中编写它,它应该可以工作
–
|
更新
=LET(
aggFunc; LAMBDA(tbl; criteriaSpec; retCols;
LET(
header; TAKE(tbl; 1);
data; DROP(tbl; 1);
criteriaSpec; TEXTSPLIT(criteriaSpec; "=");
title; INDEX(criteriaSpec; 1; 1);
toFind; INDEX(criteriaSpec; 1; 2);
titleCol; XMATCH(title; header);
criteria; IF(
toFind = "";
SEQUENCE(ROWS(data); ; TRUE; 0);
CHOOSECOLS(data; titleCol) = toFind
);
uFound; UNIQUE(FILTER(CHOOSECOLS(data; titleCol); criteria));
aggCol; LAMBDA(col; TEXTJOIN(" / "; TRUE; UNIQUE(col)));
aggForTitle; LAMBDA(acc; titleVal;
VSTACK(
acc;
LET(
filtered; FILTER(
CHOOSECOLS(data; retCols);
CHOOSECOLS(data; titleCol) = titleVal
);
HSTACK(titleVal; BYCOL(filtered; aggCol))
)
)
);
REDUCE(
CHOOSECOLS(header; titleCol; retCols);
uFound;
aggForTitle
)
)
);
aggFunc(TAB_34[#All]; "Name="; {2; 3})
)
您收到#CALC!
错误,因为从 返回了嵌套数组MAP
。因此,稍微修改一下,aggFunc
使用 累积结果VSTACK
,并使用 堆叠结果REDUCE
:
替换,
为;
,因此如果发现任何错误,请更正。
=LET(
Names; TAB[Name];
uNames; UNIQUE(Names);
numCols; SEQUENCE(COLUMNS(TAB[#Data]) - 1; ; 2);
aggfunc; LAMBDA(acc; name;
VSTACK(
acc;
HSTACK(
BYCOL(
CHOOSECOLS(TAB; numCols);
LAMBDA(col;
TEXTJOIN(
" / ";
TRUE;
UNIQUE(FILTER(col; Names = name))
)
)
)
)
)
);
HSTACK(
VSTACK(CHOOSECOLS(TAB[#Headers]; 1); uNames);
REDUCE(CHOOSECOLS(TAB[#Headers]; numCols); uNames; aggfunc)
)
)
已更新 2024-09-15
=LET(
Names, TAB_5[Name],
uNames, UNIQUE(Names),
numCols, SEQUENCE(COLUMNS(TAB_5[#Data]) - 1, , 2),
aggCol, LAMBDA(col, TEXTJOIN(" / ", TRUE, UNIQUE(col))),
aggfunc, LAMBDA(acc, name,
VSTACK(
acc,
LET(
filtered, FILTER(CHOOSECOLS(TAB_5, numCols), Names = name),
HSTACK(BYCOL(filtered, aggCol))
)
)
),
HSTACK(
VSTACK(CHOOSECOLS(TAB_5[#Headers], 1), uNames),
REDUCE(CHOOSECOLS(TAB_5[#Headers], numCols), uNames, aggfunc)
)
)
7
-
你好@nkalvi,它运行良好。我可以添加一个新列,它出现在输出中。非常感谢你抽出时间!
–
-
不客气!感谢您提供数据和步骤 – 这让开始实验变得更容易。我做了一个小修改,请看看是否有帮助。
– -
我需要使其更加灵活并使用“命名公式”。但想法是,假设我有一个名为“Compact”的公式,它具有类似 Compact(TAB;“Type=nt”;“Service”;…) 的参数。我像这样修改了您的第一个代码(我还没有分析您的第二个代码)
=LAMBDA(TAB;Criteria;retCol1; LET( Title;CHOOSECOLS(TEXTSPLIT(Criteria;"=");1); iTitle; MATCH(Title; TAB[#Headers];0); ToFind;CHOOSECOLS(TEXTSPLIT(Criteria;"=");2); Names;CHOOSECOLS(TAB;iTitle); uNames; IF(ToFind="";UNIQUE(Names);ToFind); numCols;{2;3}; ...
(第一部分)
–
-
“` aggfunc; LAMBDA(acc;name; VSTACK(acc;HSTACK(BYCOL(CHOOSECOLS(TAB; numCols); LAMBDA(col;TEXTJOIN(” / “;TRUE;UNIQUE(SORT(FILTER(col; Names = name)))))))) ); HSTACK( VSTACK(CHOOSECOLS(TAB[#Headers]; iTitle); uNames); REDUCE(CHOOSECOLS(TAB[#Headers]; numCols); uNames; aggfunc) ) ))(TAB;”Type=win”;”Environment”)“` 您可能注意到第一个参数是表的名称,第二个参数是条件,第三个参数是返回列的标题(目前我将它们硬编码为numCols;{2;3}但我正在努力。
–
-
发布了一份快速草稿 – 请让我知道它是否有帮助。
–
|
根据@nkalvi的建议,我改进了公式,使其更加灵活(我添加了更多列
K1电池上的公式是:
=LAMBDA(TAB;Criteria;retCol1;
LET(
Title;CHOOSECOLS(TEXTSPLIT(Criteria;"=");1);
iTitle; MATCH(Title; TAB[#Headers];0);
ToFind;CHOOSECOLS(TEXTSPLIT(Criteria;"=");2);
Names;CHOOSECOLS(TAB;iTitle);
uNames; IF(ToFind="";UNIQUE(Names);ToFind);
numCols; MATCH(retCol1; TAB[#Headers];0);
aggfunc; LAMBDA(acc;name;
VSTACK(
acc;
HSTACK(
BYCOL(
CHOOSECOLS(TAB; numCols);
LAMBDA(col;TEXTJOIN(" / ";TRUE;UNIQUE(SORT(FILTER(col; Names = name))))))))
);
HSTACK(
VSTACK(CHOOSECOLS(TAB[#Headers]; iTitle); uNames);
REDUCE(CHOOSECOLS(TAB[#Headers]; numCols); uNames; aggfunc)
)
))(TAB;I2;G2#)
现在,以下是创建“命名公式”的一些步骤:
- 转到菜单“公式”,单击“名称管理器”,然后单击按钮“新建…”
- 插入“COMPACT”作为名称
- 复制上述除(TAB;I2;G2#)之外的所有代码并将其粘贴到“引用:”字段 + 确定 + 关闭
现在,如果将公式放在=COMPACT(TAB;I2;G2#)
单元格K2上(结果显示在屏幕截图中。
参数解释:
- 第一:表的名称
- 第二个:条件([Column_Name] = [Value_to_find],如果省略 [Value_to_find],则它将返回与 Column_Name 相关的所有唯一值
- 第三:是要返回的列名称范围
PS:在公式K9中,我使用了=COMPACT(TAB;I8;G8#)
但是我需要包装所有公式以避免重复,所以它变成=UNIQUE(COMPACT(TAB;I8;G8#))
谢谢大家,如果您有优化公式的想法,我们将欢迎您:)
|
|