没有 VBA 的迭代/循环替换

Posted

技术标签:

【中文标题】没有 VBA 的迭代/循环替换【英文标题】:Iterative/Looped Substitute without VBA 【发布时间】:2019-01-22 11:58:38 【问题描述】:

简略问题:

如果我有一个串联的字符串“|#|#|#|...|#|”,我如何对每个数字应用一个乘数并更新串联的文本?例如,对于 |4|12|8|,乘以因子 2 并将连接的文本更新为 |8|24|16|。

背景

我有三列感兴趣。第一列包含日期,第二列包含金额或因子,第三列将数据连接成格式“|#|#|...|#|” (例如,|2|5|、|2|5|12|、|4|12| 等)。有时,需要对级联数据应用乘数,并且需要相应地更新各个数字。

一个例子是——

Date        Amt     Concatenated Data
01/01/18    2       |2|
01/05/18    5       |2|5|
02/06/18    12      |2|5|12|
03/25/18    -3      |4|12|
03/31/18    8       |4|12|8|
04/01/18    F2      |8|24|16|  (factor of 2 applied)
04/15/18    12      |8|24|16|12|
04/01/18    F1/4    |2|6|4|3|  (factor of 1/4 applied)

使用公式,我如何将因子应用于连接数据,并更新各个数字?

我受以下条件的约束:

Excel 2007,所以没有 TEXTJOIN 函数 没有 VBA 或 UDF(由于安全策略) 个别数字是动态的(即,我不能为 SUBSTITUTE 公式的“old_text”参数使用静态值) 连接数据中单个数字的数量也是动态的(可能包含一个数字,也可能包含几十个不同的数字)

我可以使用数组公式提取单个数字。我什至可以将这些数字乘以因子以产生数组结果。但是,我无法重建连接的数据,因为 CONCATENATE 不适用于数组。我也尝试过 SUBSTITUTE,但我无法遍历“|”分隔符。我只能替换给定的段(例如,将“|2|”的所有条目更改为“|4|”)。嵌套 SUBSTITUTE 或使用单个列将不起作用,因为它可能涉及数十个实例。

只是添加一些关于连接数据的信息:

Amt>0,然后将值连接到前一个连接值的末尾 Amt Amt 减少仅限于先前 CV 的单个数字的总和(例如,对于 |4|12|,减少不能超过 16) Amt=F#,表示乘数,CV的数字需要更新 CV 没有最大值(可能有几十到几百个单独的数字,数字从 1 到 100,000+),除了 Excel 本身对字符串长度应用的任何最大值

【问题讨论】:

你能解释一下逻辑吗?例如,为什么我们从|2|5|12| 转到|4|12| 这些数字本质上是在记录单个交易。正数连接到前一个条目的末尾。但是,负数会减少现有条目。 怎么样?看这个例子还很不清楚。请edit您的问题与解释 连接的条目跟踪各个交易的余额。例如,|2|5|12|表示 2、5 和 12 的现有余额。当 -3 的条目出现在 18 年 3 月 25 日时,它将 2 减少为 0(消除该余额),并将 5 减少为 4。连接条目被调整为反映新的余额。就各自的余额而言,它看起来像 |0|4|12,但余额为 |0|被删除。 对帐户进行递减和应用因子的复杂性要求采用迭代方法,尤其是因为连接帐户的数量是可变的。我无法想象一个解决方案,你可以用每行一个公式来做到这一点。但是,可以在AmtConcatenated Data 之间添加一堆公式列。您必须为可以连接的最大帐户数创建公式列。然后您可以有条件地将它们组合到您的|#|#|#|#|#| 字符串中。它仍然会相当复杂,但不使用 VBA 可能是可行的。 【参考方案1】:

高级

    此解决方案的四个部分 它们满足先决条件(2007 兼容性,无 VB,无 Office 365 要求,无自定义 VB 函数,提供完全“动态”性质的可变长度单元格连接) 警告:根据最佳知识/研究,不存在简约的单细胞功能,因此提出了一个临时步骤) 还有一个警告:我认为将图表包裹在分隔数据周围的简单“破解”是没有问题的(请参阅下面的“其他/各种”☺)

第 1-4 部分

下面的1-4部分是与以下屏幕截图相关的功能:

我还上传/修改以满足 Google 表格的要求(请参阅 here) 第 1 部分和第 2 部分:

同样的,他们依靠 FilterXML 技术来计算组件/术语,并分别拆分单元格:

第 1 部分:

=COUNT(2*TRANSPOSE(FILTERXML("<AllText><Num>"&SUBSTITUTE(LEFT(MID(D12,2,LEN(D12)-1),LEN(MID(D12,2,LEN(D12)-1))-1),"|","</Num><Num>")&"</Num></AllText>","//Num")))

注意:谷歌表格无法识别 FilterXML,因此相应地修改了技术/功能。例如,上面可以使用第 2 部分中拆分单元格上的 counta 来确定(比上面提出的方法更容易/更简单,尽管考虑到位于拆分单元格右侧的任何单元格都会干扰这种方法的普通功能,但鲁棒性较差) .

第 2 部分:

这要么是一种手动方法,要么是一系列花哨的“中间”和/或替代/左/右函数,要么是以下 FilterXML 代码,根据各种来源(例如 here)应该与 Excel 2007 兼容:

=IF(LEFT(C12,1)="F",1*SUBSTITUTE(C12,"F",""),1)*TRANSPOSE(FILTERXML("<AllText><Num>"&SUBSTITUTE(LEFT(MID(D12,2,LEN(D12)-1),LEN(MID(D12,2,LEN(D12)-1))-1),"|","</Num><Num>")&"</Num></AllText>","//Num"))

可以看出与第 1 部分(re:FilterXML)的共同点 - 唯一的区别是计数(第 1 部分)已被转换(乘法因子,如 O.P 的 Q 中给出)所取代。

第三部分

这里没什么特别的 - 一个简单的连接(这与“递归”替换函数相去甚远,我知道,但是嘿 - 它可以解决问题,并且始终可以放置在原始工作表的镜像副本中以避免空间问题/细胞交互问题)

=IF(H12="","",IF(G24="","|","")&G24&H12&"|")

第四部分

由于第 1 部分中导出的术语数量,偏移函数可以轻松确定与“转换”值的串联“构建”相关的最终单元格(根据第 3 部分):

=OFFSET(H31,0,E31-1,1,1)

其他/各种

存在各种其他建议和“解决方法”;不幸的是,这些似乎在某种方式上都达不到所提出的先决条件,很明显:

a) 基于函数/公式 b) 没有 VB c) Excel 2007 d) 动态(可变/未知数量的术语)

    手动:例如function = concatenate(transpose(desired range)),然后是 concatenate 函数的分量,然后按 F9 转换为计算值,这些值很容易应用于 concatenate 函数。缺点:与“自动化解决方案”相关的耗时(需要针对每个适用的玩具进行)。优势:不需要额外的“电子表格不动产”,在第一次实施时更快/更直接。 “累积”方法的变体:例如但是,根据第 3 部分,仅此一项并不能确保在原始串联列表中使用未知数量的术语的自动化方法。 在之前的解决方案 (here) 中提到过,但可能是您在使用早期版本的 Excel 时有资格使用 Office 365 功能(请参阅 Office Insider here) 其他建议(请注意本论坛的上方/下方)建议使用 textjoin(因此不确定这是理解问题还是什么 ☺) 是的,正如一开始提到的,您可以使用简单的图表轻松实现所需的结果!只是为了好玩,以相反的顺序对数据进行排序,并将拆分/分隔的值包含为条形图的“x 值”(根据定义,对于这种类型的图,现在将沿着普通笛卡尔 'y /垂直'轴)...

这点零分,但我认为这是一个有趣的发现! (如果仍有疑问,如果我没有杀死除了轴标签之外的所有东西,“图表”会是什么样子......):

以上相关其他项目的大量参考资料,包括研究领域,如下:

Excel Champs *** - alternative applications for FilterXML

还有一件事……

在真正的哥伦布风格的作案手法中,考虑的其他想法/方法:

数据透视表的应用? 构造矩阵:我得到了一个包含一系列偏移函数的解决方案,但想不出一种可行的方法来实现给定的空间问题 通过求和将拆分单元格转换为长数字:例如8 22 16 = 80 000 + 22 00 + 16。使用带有文本的替换函数(长数字,“常规”)我能够成功地为相邻的“元组”对引入分隔符(“|”)(例如 I可以得到“8|2216”、“822|16”,但随后是一个“建立”公式,其中一个单元格取决于前一个单元格的转换值,因此再次需要一个单元格,这让我回到了我设定的建议在上面 fyi - 矩阵考虑仅解决 2 的元组,对于 n 维/组合,需要在其镜像副本上“传递”一串字符 - 例如6,10,22 会超过 6,10,22,忽略重复值会产生如下梯形:
6 10 22
6 10 22
6 10 22

在副本“通过”原始(第一行)之后,我们得到了所需的组合 (22,10,6)(在“对角线”这样的矩阵上)。这类似于傅立叶变换的工作方式(有点);但除此之外,构建这样的矩阵很诱人,但现阶段无法打扰。

可能会是某人想出的一种更简单的方法(根据我考虑过的各种来源,我不会是唯一一个感到惊讶的人......)

【讨论】:

以上是关于没有 VBA 的迭代/循环替换的主要内容,如果未能解决你的问题,请参考以下文章

VBA - 如何有条件地跳过for循环迭代

将不同的函数传递到同一个迭代循环(VBA)

如果单元格内容已经通过,则 vba 下一次迭代

为 vba 使用 for 循环

queryList 一次抓取多个网页内容的方法--目前只有用循环 替换页码或者给出url循环进行 queryList没有像python一样的yied迭代方法 queryList 实现多个实例抓取

Python:替换多个 for 循环、多个迭代器