【问题标题】:Better Excel Formula for Complex Lookup用于复杂查找的更好的 Excel 公式
【发布时间】:2012-06-23 21:07:45
【问题描述】:

我正在尝试改进我继承的复杂查找过程。查找是通过几个 UDF 结合一些标准工作表函数生成的。但是,问题是当用户更新源表中的一些数据时,重新计算的时间是不可接受的。

所以,我看了看,并认为我可以编写一个更好的 Excel 公式解决方案。好吧,我确实找到了解决方案,但是 Excel 无法处理大型数据集,而且当我的 VBA 针对数据集运行公式时,它会崩溃(可以理解!)。

现在,我可以在 VBA 中完全实现这一点,但是用户必须在每次更改后按下按钮或其他东西来更新。我想要的是一种更简单的方法,如果有的话,使用一些高级 Excel 2007 公式。由于我对这些公式不太熟悉,因此我正在寻求帮助!

好的,这是我必须处理的。

源表

Tid、结算日期和月末价格(由 1、2、3 等标识的层期)在如下列中

Tid   SettleDate   1   2   3   4   5   6   7   8   9   10  ...   n

公式表

在其他列中,我有以下列

InitLayer   LiqdLayer   InstrClass   Tid   SettleDate   InitPrice   LiqdPrice   Position

我在整个数据集右侧的列中也有层号,如下所示:

1   2   3   4   5   ...   n

我需要做的是根据数据集中的一些逻辑,通过在源表上查找价格,在这些列中填写适当的价格变化。

在伪公式中,这是我需要对 FormulaSheet 中的每一层列进行的操作

If Layer < InitLayer OR Layer > LiqdLayer Then Return "-"

ElseIf Layer = InitLayer Then (Layered Price - InitPrice) * Position

     where Layered Price is obtained by finding the Intersect of the LayerNumber 
     Column and Tid Row in the SourceSheet

ElseIf Layer = LiqdLayer Then Previous Layered Price * Position

     where Previous Layered Price is obtained by finding the Intersect of the Previous   
     LayerNumber Column and Tid Row in the SourceSheet

Else (LayeredPrice - Previous Layered Price) * 6

     where Layered Price and Previous Layered Price are defined as above

End If

我确实想出了这个公式,它在小数据集上效果很好,但对于大数据集来说它toooooooooo又大又讨厌,或者只是太大而讨厌的时期!

=IF(OR(CH$3<$AT6,CH$3>$AU6),"-",IF($AT6=CH$3,(HLOOKUP(CH$3,layered_prices,RIGHT(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4),LEN(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4))-1)-1,FALSE)-$AV6)*$C6,IF($AU6=CH$3,($AW6-HLOOKUP(CG$3,layered_prices,RIGHT(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4),LEN(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4))-1)-1,FALSE))*$C6,(HLOOKUP(CH$3,layered_prices,RIGHT(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4),LEN(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4))-1)-1,FALSE)-HLOOKUP(CG$3,layered_prices,RIGHT(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4),LEN(ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4))-1)-1,FALSE))*$C6)))

公式键

CH = Layer Number
CG = Previous Layer Number
AT = InitLayer
AU = LiqdLayer
AX = InstrClass (used to find a separate lookup for Currencies)
T = Tid
G = SettleDate (used to find a separate lookup for Currencies)
AV = InitPrice
AW = LiqPrice
C = Position
layered_prices = named range for the range of prices under the layer columns in SourceSheet
layered_tid = named range for tid rows in SourceSheet
layered_curtid = named range for currency tid rows in Source Sheet (just a separte lookup if InstrType = Currency, formula the same

是否有任何其他公式或公式组合可以让我以比我创造的怪物更有效的方式获得我想要的东西?

【问题讨论】:

  • 数据集有多大?如果超过 200k 行,作为公式可能不可行......
  • 虽然我们可能会在少数情况下达到这个数字,但大多数不会达到这个数字。我一直在探索查找和参考部分,我可能会做一些事情……如果我找到更好的答案,我会发布。
  • justpaste.it 可用于直接从/粘贴到 Excel,我自己用过几次。
  • 根据我的经验 index(match()) 减少了 VLOOKUP 和 HLOOKUP 的大量时间,但我不知道它是否会对你产生足够大的影响
  • 我通常发现将这样的长公式拆分成几列更容易。这实现了两件事,它使单步执行公式变得更容易,并且通常允许您重用条件而不是重复它们。在这种情况下,您将受益,因为您的公式似乎在多个地方重复了相同的 hlookup。可能值得尝试将其拆分,它可能运行得更快。如上所述,查找会占用内存,如果可能的话,它们的使用应该受到限制。你能重新排列你的公式以减少使用这些函数吗?

标签: excel-2007 excel-formula


【解决方案1】:

我同意 Kharoof 的评论。您应该将此公式分成几列。据我计算,您还需要 4 列。好处有两个:1) 您的公式变得更短,因为您不会一遍又一遍地重复相同的函数;2) 您可以节省内存,因为 Excel 将计算一次而不是多次。

例如,您调用完全相同的ADDRESS 函数四次。 Excel 在评估公式时不会“记住”它是什么,因此它每次都重新计算它。如果你把它放在它自己的单元格中,那么 Excel 将在任何依赖它的单元格之前评估该单元格,并将其存储为一个值而不是公式。当其他单元格引用它时,Excel 将提供预先评估的结果。


首先,您的最终公式应该是:([括号] 中的名称表示辅助列适合那里。它将是一些单元格引用,例如 CI$3,但我不确定您想要的位置换句话说。您必须根据添加这些列的位置来更新这些引用。)

=IF(OR(CH$3<$AT6,CH$3>$AU6),"-",IF($AT6=CH$3,([LayerNumber]-$AV6)*$C6,IF($AU6=CH$3,($AW6-[PreviousLayerNumber])*$C6,([LayerNumber]-[PreviousLayerNumber])*$C6)))

这里有四个辅助列:

[ADDRESS] = ADDRESS(MATCH(IF($AX6="CUR",$T6 & " " & $G6,$T6),IF($AX6="CUR",layered_curtid,layered_tid),1),1,4)
[RIGHT] = RIGHT([ADDRESS],LEN([ADDRESS])-1)
[LayerNumber] = HLOOKUP(CH$3,layered_prices,[RIGHT]-1,FALSE)
[PreviousLayerNumber] = HLOOKUP(CG$3,layered_prices,[RIGHT]-1,FALSE)

通过拆分,公式的每个步骤都更易于遵循/调试,并且在 Excel 中处理起来也更快。如果您想在数量上有所改进,五个公式的组合将比您现在拥有的单个公式短 70% 左右。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-08-31
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多