Reputation: 109
I have a dictionary
tickers = {'BTC': [200, 149, 98, 44], 'ETH': [200, 320, 405, 460]}
now
and prev
are elements of lists.
We compare this element and previous element in list.
For example in BTC:
149 with 200
98 with 149
44 with 98
# check state . describe state
def check_state(now, prev):
state = None
if now >= prev:
if now <= 1.5 * prev:
state = 0
if now >= 1.5 * prev:
state = 1
if now < prev:
if now * 1.5 >= prev:
state = 2
if now * 1.5 < prev:
state = 3
return state
I want to get new dictionary with tickers and states in every day. First day no state because first day didn't have previous.
tickers_state = {'BTC': [None, 3, 3, 3], 'ETH': [None, 1, 0, 0]}
where elements are state in every day of each ticker.
How can i do it?
Upvotes: 0
Views: 1358
Reputation: 15120
You could compare each consecutive pair of values in your lists with a function that loops through the list and uses enumerate to enable access to the previous list item for comparison. Then use dict comprehension with your function to produce a mapped version of your original dict with the compared values.
In the example below, it loops through a slice of the list starting with the second list item so the previous element is accessed by the current value of i
because the slice has essentially shifted the index values by 1.
tickers = {'BTC': [200, 149, 98, 44], 'ETH': [200, 320, 405, 460]}
def check_states(data):
states = [None]
for i, n in enumerate(data[1:]):
state = None
p = data[i]
(low, high) = (p / 1.5, p * 1.5)
if n >= p:
state = 0 if n <= high else 1
else:
state = 2 if n >= low else 3
states.append(state)
return states
tickers_state = {k: check_states(v) for k, v in tickers.items()}
print(tickers_state)
# OUTPUT
# {'BTC': [None, 2, 3, 3], 'ETH': [None, 1, 0, 0]}
Upvotes: 1
Reputation: 13697
If you reverse the order of input arguments of check_state
from def check_state(now, prev):
to def check_state(prev, now):
then the problem of applying a function to consecutive pairs of values of your lists becomes quite easy. I came up with the following function:
import itertools
def apply_pairwise(values,
function):
"""
Applies function to consecutive pairs of elements from an input list
"""
def pairwise(iterable):
"""
s -> (s0,s1), (s1,s2), (s2,s3), ...
"""
a, b = itertools.tee(iterable)
next(b, None)
return zip(a, b)
yield from itertools.chain([None],
itertools.starmap(function, pairwise(values)))
Examples of usage:
>>> btc = [200, 149, 98, 44]
>>> list(apply_pairwise(btc, check_state))
[None, 2, 3, 3]
>>> eth = [200, 320, 405, 460]
>>> list(apply_pairwise(eth, check_state))
[None, 1, 0, 0]
If you can't reverse the inputs:
If it's impossible to change the order of inputs, we could adopt our function a bit:
import itertools
def apply_pairwise(values,
function,
*,
reverse=False):
"""
Applies function to consecutive pairs of elements from an input list
"""
def pairwise(iterable):
"""
s -> (s0,s1), (s1,s2), (s2,s3), ...
or -> (s1,s0), (s2,s1), (s3,s2), ... if reverse
"""
a, b = itertools.tee(iterable)
next(b, None)
if reverse:
return zip(b, a)
return zip(a, b)
yield from itertools.chain([None],
itertools.starmap(function, pairwise(values)))
and you could use it like this:
>>> btc = [200, 149, 98, 44]
>>> list(apply_pairwise(btc, check_state, reverse=True))
[None, 2, 3, 3]
>>> eth = [200, 320, 405, 460]
>>> list(apply_pairwise(eth, check_state, reverse=True))
[None, 1, 0, 0]
Explanation:
In order to get consecutive pairs of elements, we could use a helper function from recipes of itertools
:
def pairwise(iterable):
"s -> (s0,s1), (s1,s2), (s2, s3), ..."
a, b = tee(iterable)
next(b, None)
return zip(a, b)
It works like this:
>>> list(pairwise(range(5)))
[(0, 1), (1, 2), (2, 3), (3, 4)]
Now for each pair of elements we would like to apply your check_state
function. Here itertools.starmap
can be useful. It works like this:
>>> list(itertools.starmap(pow, [(2, 3), (2, 10), (10, 3), (3, 4)]))
[8, 1024, 1000, 81]
The only thing left is to prepend the values yielded by starmap
by None
. As starmap
makes an iterator, we could use itertools.chain
to combine the first None
with the rest of the elements.
P.S.: Applying this to values of your tickers
dict should be easy enough. I will leave it to you.
Upvotes: 3