Mor*_*aki 5 worksheet-function microsoft-excel
给定下表,我想找到满足输入x
值和给定容差的最高标头编号(由 中 的值J4
表示)和伴随的行索引(由 中y
的值表示J5
):I2
J2
正如您所看到的,表中有两个值满足输入值和容差:cellsF3
和G3
。然而,由于 中的标题行号G2
(48) 高于F2
(44),因此我们将作为最终解决方案,并打印出和G3
中各自的数字。J4
J5
我有一个解决方案,使用具有绝对值的中间矩阵并减去输入值。G
然后在一个冗长的公式中使用 IF 和 SMALL向后遍历每一行B
(非常有限且相当硬编码)。
我的愿望是使用现代 Excel 函数(LAMBDA、MAP 等)将该表转换为记录列表,然后简单地输出相应的值。本质上,将表转换为内存中的记录结构,而工作表中没有中间矩阵,如下所示(G2
、G3
和 的转换示例E7
):
List<Record> vals = [
(36.22, 48, 1),
(69.31, 48, 2),
...
(169.99, 40, 6),
...
]
Run Code Online (Sandbox Code Playgroud)
使用此结构,可以更轻松地找到输入值和容差范围内的第一个值,并输出 x和 yvals.[field1]
的相应列表条目。vals.[field2]
vals.[field3]
使用现代 Excel 函数和内存计算可以优雅地完成此操作吗?
输入数据可以在这里找到: https: //pastebin.com/JRaA14e8
28 | 32 | 36 | 40 | 44 | 48 | |
---|---|---|---|---|---|---|
1 | 23.02 | 25.66 | 28.30 | 30.94 | 33.58 | 36.22 |
2 | 42.91 | 48.19 | 53.47 | 58.75 | 64.03 | 69.31 |
3 | 62.80 | 70.72 | 78.64 | 86.56 | 94.48 | 102.40 |
4 | 82.69 | 93.25 | 103.81 | 114.37 | 124.93 | 135.49 |
5 | 102.58 | 115.78 | 128.98 | 142.18 | 155.38 | 168.58 |
6 | 122.47 | 138.31 | 154.15 | 169.99 | 185.83 | 201.67 |
7 | 142.36 | 160.84 | 179.32 | 197.80 | 216.28 | 234.76 |
8 | 162.25 | 183.37 | 204.49 | 225.61 | 246.73 | 267.85 |
9 | 182.14 | 205.90 | 229.66 | 253.42 | 277.18 | 300.94 |
10 | 202.03 | 228.43 | 254.83 | 281.23 | 307.63 | 334.03 |
11 | 221.92 | 250.96 | 280.00 | 309.04 | 338.08 | 367.12 |
12 | 241.81 | 273.49 | 305.17 | 336.85 | 368.53 | 400.21 |
13 | 261.70 | 296.02 | 330.34 | 364.66 | 398.98 | 433.30 |
编辑 1:附加背景和示例
我最初的问题似乎不清楚哪种优化条件普遍存在以及为什么。这个例子是可折叠/可伸缩太阳能电池板经济可行性计算工具链的一小部分。标题行 ( 1:1
) 表示每个轨道的模块/面板数量,( A:A
) 列表示轨道数量。因此,x 实际上表示每个轨道的模块或面板,y 表示轨道的数量。
在这个特定的工业案例模型中,对于钢支撑结构来说,每条轨道拥有更高密度的太阳能电池板总是比拥有更多轨道更经济。
当使用元组 (200,3) 作为(输入值,公差)时,三个结果元组符合选择标准:
(28,10)
(40,7)
(48,6)
Run Code Online (Sandbox Code Playgroud)
由于 48 个模块/轨道提供的密度高于 40 或 28 个模块,因此正确的最终解决方案是 x=48 和 y=6。
所提供的解决方案的当前情况如下(尽管我可能没有正确集成 Redy 的解决方案):
编辑 2:工作建议的解决方案
似乎至少有两个可行的解决方案:
注意:此答案依赖于拥有最新版本的 Excel for Microsoft 365(已测试)或可能的 Excel for the Web(未测试)。
编辑以考虑多个匹配条件中的“最大列索引”:
调整方法以选择与最大列标题匹配的方法,这应该适用于单元格 J4:
=LET(
data, A1:G14,
row_headers, DROP(TAKE(data, , 1), 1),
col_headers, DROP(TAKE(data, 1), , 1),
d, DROP(data, 1, 1),
v, I2,
tol, J2,
cols, COLUMNS(d),
ascol, TOCOL(d),
position, SEQUENCE(ROWS(ascol)),
row, ROUNDUP(position / cols, 0),
col, MOD(position + cols - 1, cols) + 1,
arr, HSTACK(ascol, row, col),
include, BYROW(ascol, LAMBDA(x, AND(x >= (v - tol), x <= (v + tol)))),
matches, FILTER(arr, include),
sorted, SORT(matches, {3, 2}, {-1, -1}),
is_best, TAKE(sorted, 1),
result, VSTACK(
INDEX(col_headers, 1, INDEX(is_best, 1, 3)),
INDEX(row_headers, INDEX(is_best, 1, 2), 1),
INDEX(is_best, 1, 1)
),
result
)
Run Code Online (Sandbox Code Playgroud)
或者作为 LAMBDA:
get_best_match = LAMBDA(data, value, tolerance,
LET(
//get the headers
row_headers, DROP(TAKE(data, , 1), 1),
col_headers, DROP(TAKE(data, 1), , 1),
//just the search array
d, DROP(data, 1, 1),
v, value,
tol, tolerance,
cols, COLUMNS(d),
//convert the array to a column with row and column positions added
ascol, TOCOL(d),
position, SEQUENCE(ROWS(ascol)),
row, ROUNDUP(position / cols, 0),
col, MOD(position + cols - 1, cols) + 1,
arr, HSTACK(ascol, row, col),
//filter for those rows that meet the criteria
include, BYROW(ascol, LAMBDA(x, AND(x >= (v - tol), x <= (v + tol)))),
matches, FILTER(arr, include),
//sort descending on column header, row header
sorted, SORT(matches, {3, 2}, {-1, -1}),
//take the first row of the sorted matches
is_best, TAKE(sorted, 1),
result, VSTACK(
INDEX(col_headers, 1, INDEX(is_best, 1, 3)),
INDEX(row_headers, INDEX(is_best, 1, 2), 1),
INDEX(is_best, 1, 1)
),
result
)
);
Run Code Online (Sandbox Code Playgroud)
添加新标准之前的原始答案:
我相信这将在单元格 J4 中起作用:
=LET(
data, A1:G14,
row_headers, DROP(TAKE(data, , 1), 1),
col_headers, DROP(TAKE(data, 1), , 1),
d, DROP(data, 1, 1),
v, I2,
tol, J2,
cols, COLUMNS(d),
matches, MAP(d, LAMBDA(x, AND(x >= (v - tol), x <= (v + tol)))),
is_best, d = MAX(d * matches),
best_position, MAX(is_best * SEQUENCE(ROWS(d), cols)),
y, ROUNDUP(best_position / cols, 0),
x, MOD(best_position + cols - 1, cols) + 1,
result, VSTACK(
INDEX(col_headers, 1, x),
INDEX(row_headers, y, 1),
MAX(d * matches)
),
result
)
Run Code Online (Sandbox Code Playgroud)
我们可以在高级公式环境中对其进行注释并保存为命名的 LAMBDA,如下所示:
get_headers = LAMBDA(data,test,tolerance,
LET(
//get just the row index from column 1, rows 2:max
row_headers, DROP(TAKE(data, , 1), 1),
//get just the column headers from row 1, columns 2:max
col_headers, DROP(TAKE(data, 1), , 1),
//get just the array of data to test against
d, DROP(data, 1, 1),
//get the number of columns in the array (the )
cols, COLUMNS(d),
//test each value against the boundaries
matches, MAP(d, LAMBDA(x, AND(x >= (test - tolerance), x <= (test + tolerance)))),
//identify the best value
is_best, d = MAX(d * matches),
//find the position of the best value
best_position, MAX(is_best * SEQUENCE(ROWS(d), cols)),
//identify the row index
y, ROUNDUP(best_position / cols, 0),
//identify the column index
x, MOD(best_position + cols - 1, cols) + 1,
//return the column header, the row header and the best value
result, VSTACK(
INDEX(col_headers, 1, x),
INDEX(row_headers, y, 1),
MAX(d * matches)
),
result
)
)
Run Code Online (Sandbox Code Playgroud)