I have several indicators which need to be "always up to date". Ie when anything is changed I need to recalculate "dependent". I have several levels where each next level should be calculated only when previous level is calculated. Let me explain by this shining picture:
At some point Assume that Franc changed. Then we should:
Or, if Peso, Franc and Dinar are changed all at once then we should:
So whenever anything at the Level 0
is chagned we should recalculate all other levels. But
The most straightforward solution would be:
I guess that my problem is kind of well-known and probably you can suggest me general well-known solution. I don't want to reinvent the wheel :) Thanks!
I think the level-based approach is decent, on the assumption that listeners are always on a lower level.
Have a 2D array containing your actual data, the first index is the level, the second is the position on the level. Let each element have a willBeRecalculated
flag.
Have a toBeRecalculated
list for each level (so an array of lists).
For each element, have a list of elements (the listeners) containing 2 integers - one for level and one for index.
For each element to be modified, add the element to toBeRecalculated
on the appropriate level and set willBeRecalculated
to true.
Then go through toBeRecalculated
from the first to the last level, recalculating each element, setting its willBeRecalculated
to false and, for each listener, looking up the applicable element, if willBeRecalculated
is true, do nothing, otherwise, set willBeRecalculated
to true and add it to toBeRecalculated
on its (the listener's) level.
This approach doesn't go through all the data to check what needs to be modified / has been modified, it only checks applicable elements, and there are no repeated calculations.
For this:
(For my abbreviations I simply took the first letter of each word. I'm using 0-indexed arrays)
Actual data:
[[E, U, P, F, D],
[E+U, F/D],
[E/E+D, F/D/P],
[P+E/E+U]
]
Listeners:
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)]
Modifying E
and U
:
Add E
and U
to toBeRecalculated[0]
and set willBeRecalculated
to true for both.
Go through toBeRecalculated[0]
.
When modifying E
, set willBeRecalculated
to false for it and set E+U
's willBeRecalculated
to true and add it to toBeRecalculated[1]
and set E/E+U
's willBeRecalculated
to true and add it to toBeRecalculated[2]
.
When modifying U
, set willBeRecalculated
to false for it and we check E+U
's willBeRecalculated
and see it's true so do nothing.
Then go through toBeRecalculated[1]
. When modifying E+U
, set willBeRecalculated
to false for it and check E/E+U
's willBeRecalculated
and see it's true so do nothing.
It might be better to have the listeners be pointers to the elements instead of a level and an index variable.
Well, when you say you are dealing with levels, some sort of tree data structure comes to mind..
But for your problem, I think it would work to model some sort of directed acyclic graph.
Your graph might look something like this (all directions are downward)..
root
/ / | \ \
E U P F D
\ /
\ /
(Euro + Usd)
If you traverse this like you would a tree data structure, you will update each conversion rate exactly once for each update to the currency.
What you are describing can easily be accomplished in a reactive programming language.
The QML of Qt also provides a property binding mechanism that accomplishes this for a UI.
Looking at the implementations of Qt property bindings and other reactive languages may give you some implementation ideas.
The Wikipedia page identifies libraries for reactive programming in Javascript, .NET, Python, Java, C++, and many other languages as well.
I think you can use polymorphism here. Have a list of Currencies, each of which holds a vector with pointers (to the base class) of all depedant elements.
The base class forces them to include a function update()
which is called everytime the current currency is updated.
The depedant elements in turn have pointers for each currency they depend on and use these to update themselves in their update()
implementation.
#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();
}
}
This enables:
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;
}
Printing:
3
9
Perhaps you can have a std::vector<std::weak_ptr>
of your currencies while each node holds a std::shared_ptr
for each currency so the currencies may not got out of scope/be destroyed unless there are no more nodes refering to them
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.