建议如何保持“计算”很多“依赖”参数

时间:2013-07-18 13:59:19

标签: algorithm

我有几个指标需要“始终保持最新”。即当任何事情发生变化时,我需要重新计算“依赖”。我有几个级别,只有在计算前一级别时才应计算每个下一级别。让我用这幅闪亮的画面解释一下:

Design

在某些时候假设法郎改变了。然后我们应该:

  1. calc Franc / Dinar
  2. calc Franc / Dinar / Peso
  3. 或者,如果Peso,Franc和Dinar一下子改变了,那么我们应该:

    1. calc Franc / Dinar
    2. calc Franc / Dinar / Peso
    3. calc Peso + Euro /(Euro + Usd)
    4. 因此,只要Level 0处的任何事情被打开,我们就应该重新计算所有其他级别。但

      • 我们应该只计算所需的项目。如果欧元改变,我们不需要重新计算法郎/第纳尔
      • 我们不应该计算任何超过一次的东西。如果欧元和美元立即改变,我们应该只计算一次欧元+美元(不是两次)。

      最直接的解决方案是:

      • 将每个级别存储在数组
      • 对于来自下一级别的数组音轨“听众”中的每个项目(可能很难,因为例如Peso有来自不同级别的听众 - 来自Level2的Franc / Dinar / Peso和来自Level 3的Peso + Euro /(Euro + Usd),所以需要两个dimmension数组..)
      • 如果重新计算项目,则将所有侦听器标记为重新计算
      • 从0级转到最后一级并重新计算标记为重新计算的项目(最初更新的项目是要重新计算的市场,例如Peso)。

      我想我的问题很有名,可能你可以建议我一般众所周知的解决方案。我不想重新发明轮子:)谢谢!

4 个答案:

答案 0 :(得分:2)

我认为基于等级的方法是不错的,假设听众总是处于较低的水平。

想法:

有一个包含实际数据的二维数组,第一个索引是级别,第二个是级别上的位置。让每个元素都有一个willBeRecalculated标记。

每个级别都有一个toBeRecalculated列表(所以列表数组)。

对于每个元素,都有一个包含2个整数的元素列表(侦听器) - 一个用于级别,一个用于索引。

对于要修改的每个元素,将元素添加到适当级别的toBeRecalculated并将willBeRecalculated设置为true。

然后从第一级到最后一级执行toBeRecalculated,重新计算每个元素,将其willBeRecalculated设置为false,并为每个侦听器查找适用的元素,如果willBeRecalculated是的,什么都不做,否则,将willBeRecalculated设置为true并将其添加到{(1}}的(听众)级别。

这种方法不会通过所有数据来检查需要修改/修改的内容,它只检查适用的元素,并且没有重复的计算。

实施例

为此:

(对于我的缩写,我只是取了每个单词的第一个字母。我正在使用0索引数组)

实际数据:

toBeRecalculated

<强>监听器:

[[E, U, P, F, D],
 [E+U, F/D],
 [E/E+D, F/D/P],
 [P+E/E+U]
]

修改E:[(1,0), (2,0)] // E+U and E/E+U U:[(1,0)] // E+U P:[(2,1), (3,0)] F:[(1,1)] D:[(1,1)] E+U:[(2,0)] F/D:[(2,1)] E/E+U:[(3,0)] E

UE添加到U并将toBeRecalculated[0]设置为true。

浏览willBeRecalculated

修改toBeRecalculated[0]时,将E设置为false并将willBeRecalculated的{​​{1}}设置为true并将其添加到E+U并设置{{ 1}}将willBeRecalculated设为true并将其添加到toBeRecalculated[1]

修改E/E+U时,请将willBeRecalculated设置为false,然后检查toBeRecalculated[2]的{​​{1}}并查看是真的,不要做任何事情。

然后浏览U。在修改willBeRecalculated时,请将E+U设置为false并检查willBeRecalculated的{​​{1}}并查看它是真的,不要做任何事情。

注意:

让侦听器成为指向元素而不是级别和索引变量的指针可能更好。

答案 1 :(得分:2)

好吧,当你说你正在处理关卡时,会想到某种树数据结构。

但是对于你的问题,我认为它可以模拟某种有向无环图。

您的图表可能看起来像这样(所有方向都向下)..

                             root 
                   /     /     |     \     \
                 E      U      P     F      D
                 \     /
                  \   /
              (Euro + Usd)

如果您像树形数据结构一样遍历此项,则每次更新货币时,您都会更新每个转化率一次。

答案 2 :(得分:0)

您所描述的内容可以通过reactive programming language.

轻松完成

Qt的QML还提供了一种属性绑定机制,可以为UI完成此操作。

查看Qt属性绑定和其他反应式语言的实现可能会为您提供一些实现方法。

Wikipedia页面标识了Javascript,.NET,Python,Java,C ++和许多其他语言的反应式编程库。

答案 3 :(得分:0)

我认为你可以在这里使用多态。 有一个货币列表,每个货币都有一个带有指针(到基类)的矢量所有的depedant元素。

基类强制它们包含一个函数update(),每次更新当前货币时都会调用该函数。

depedant元素反过来为他们所依赖的每种货币提供指针,并使用它们在update()实现中更新自己。

#include<iostream>
#include <vector>
class c_node_combi_base;
class currency
{
  std::vector<c_node_combi_base*> m_dependant;
  double m_val;
public:
  double value (void) const { return m_val; }
  void reg (c_node_combi_base * p) { m_dependant.push_back(p); }
  void update (double val);
};
class c_node_combi_base
{
  std::vector<currency*> currencies;
public:
  virtual void update (void) = 0;
};

template<size_t N, typename OP> // templated to differentiate types of nodes
class currency_node : public c_node_combi_base 
{ 
};

struct divide_d 
{
  double operator() (const double x, const double y) const {return x/y;}
};

template<typename OPT> // node type 2
class currency_node<2u, OPT> 
  : public c_node_combi_base
{
  currency *A, *B;
  OPT _op;
  double m_val;
public:
  currency_node (currency * a, currency * b)
    : A(a), B(b), _op(), m_val(_op(A->value(), B->value())) 
  {
    A->reg(this);
    B->reg(this);
  }
  void update (void) 
  { 
    m_val = _op(A->value(), B->value());
  }

  double value (void) { return m_val; }

};

void currency::update (double value) 
{
  m_val = value; 
  for (size_t i=0; i<m_dependant.size(); ++i)
  {
    m_dependant[i]->update();
  }
}

这样可以:

int main (void)
{
  currency franc, dinar;
  franc.update(9.9);
  dinar.update(3.3);
  currency_node<2, divide_d> franc_dinar(&franc, &dinar);
  std::cout << franc_dinar.value() << std::endl;
  dinar.update(1.1); // updates franc_dinar automatically
  std::cout << franc_dinar.value() << std::endl;
}

印刷:

  

3
  9


也许您可以拥有std::vector<std::weak_ptr>种货币,而每个节点对每种货币持有std::shared_ptr因此货币可能不会超出范围/被销毁,除非没有更多节点参考它们