A dictionary with lists as values and ascending dates as keys, that I want to understand how many times M in the total past times P, cover some of the current numbers.
For example, for L19981120: [2, 3, 5]: 2 numbers in the [2, 3, 5], appeared 3 times in the past 9 times.
The code looks verbose, and only printing some iterations, but not all.
What is the correct and better way to do so? Thank you.
data = {
"L19980909": [11,12,25],
"L19981013": [19,28,31],
"L19981016": [4,9,31],
"L19981020": [8,11,17],
"L19981023": [5,22,25],
"L19981027": [5,20,27],
"L19981030": [12,19,26],
"L19981105": [31,32,38],
"L19981109": [2,22,24],
"L19981110": [2,16,19],
"L19981113": [9,15,17],
"L19981119": [2,10,11],
"L19981120": [2,3,5],
"L19981126": [4,6,14],
"L19981127": [5,9,18],
"L19981201": [1,6,7]}
value_list = list(data.values())
for idx, (k, v) in enumerate(data.items()):
ever_more_than_times = []
for how_many_past in [7,8,9]:
if idx >= how_many_past:
past_appeared = sum(value_list[idx-how_many_past:idx],[])
for more_than_times in [2,3]:
if how_many_past > more_than_times:
for ox in list(range(1,40)):
if past_appeared.count(ox) >= more_than_times:
ever_more_than_times.append(ox)
ever_more_than_times = list(set(ever_more_than_times))
hit = len(set(ever_more_than_times) & set(v))
if hit != 0:
print (k,'$',v,'$',how_many_past,'$',more_than_times,'$',hit)
Output:
L19981105 $ [31, 32, 38] $ 9 $ 3 $ 1
L19981110 $ [2, 16, 19] $ 9 $ 3 $ 1
L19981119 $ [2, 10, 11] $ 9 $ 3 $ 1
L19981120 $ [2, 3, 5] $ 9 $ 3 $ 2
L19981127 $ [5, 9, 18] $ 9 $ 3 $ 1
CodePudding user response:
You can use a prefix-sum to count how many times a number appears, before a given index:
prefix_counter = [defaultdict(int) for k in data]
data_keys = list(data.keys())
last_key = data_keys[0]
for i, k in enumerate(data_keys[1:], start=1):
prev_counts = Counter(data[last_key])
prefix_counter[i] = defaultdict(int, prefix_counter[i-1])
for count in prev_counts:
prefix_counter[i][count] = prev_counts[i]
last_key = k
Now the prefix_counter
list looks like:
[
defaultdict(<class 'int'>, {})
defaultdict(<class 'int'>, {11: 1, 12: 1, 25: 1})
defaultdict(<class 'int'>, {11: 1, 12: 1, 25: 1, 19: 1, 28: 1, 31: 1})
defaultdict(<class 'int'>, {11: 1, 12: 1, 25: 1, 19: 1, 28: 1, 31: 2, 4: 1, 9: 1})
defaultdict(<class 'int'>, {11: 2, 12: 1, 25: 1, 19: 1, 28: 1, 31: 2, 4: 1, 9: 1, 8: 1, 17: 1})
defaultdict(<class 'int'>, {11: 2, 12: 1, 25: 2, 19: 1, 28: 1, 31: 2, 4: 1, 9: 1, 8: 1, 17: 1, 5: 1, 22: 1})
defaultdict(<class 'int'>, {11: 2, 12: 1, 25: 2, 19: 1, 28: 1, 31: 2, 4: 1, 9: 1, 8: 1, 17: 1, 5: 2, 22: 1, 20: 1, 27: 1})
defaultdict(<class 'int'>, {11: 2, 12: 2, 25: 2, 19: 2, 28: 1, 31: 2, 4: 1, 9: 1, 8: 1, 17: 1, 5: 2, 22: 1, 20: 1, 27: 1, 26: 1})
defaultdict(<class 'int'>, {11: 2, 12: 2, 25: 2, 19: 2, 28: 1, 31: 3, 4: 1, 9: 1, 8: 1, 17: 1, 5: 2, 22: 1, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1})
defaultdict(<class 'int'>, {11: 2, 12: 2, 25: 2, 19: 2, 28: 1, 31: 3, 4: 1, 9: 1, 8: 1, 17: 1, 5: 2, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 1, 24: 1})
defaultdict(<class 'int'>, {11: 2, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 1, 9: 1, 8: 1, 17: 1, 5: 2, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 2, 24: 1, 16: 1})
defaultdict(<class 'int'>, {11: 2, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 1, 9: 2, 8: 1, 17: 2, 5: 2, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 2, 24: 1, 16: 1, 15: 1})
defaultdict(<class 'int'>, {11: 3, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 1, 9: 2, 8: 1, 17: 2, 5: 2, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 3, 24: 1, 16: 1, 15: 1, 10: 1})
defaultdict(<class 'int'>, {11: 3, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 1, 9: 2, 8: 1, 17: 2, 5: 3, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 4, 24: 1, 16: 1, 15: 1, 10: 1, 3: 1})
defaultdict(<class 'int'>, {11: 3, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 2, 9: 2, 8: 1, 17: 2, 5: 3, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 4, 24: 1, 16: 1, 15: 1, 10: 1, 3: 1, 6: 1, 14: 1})
defaultdict(<class 'int'>, {11: 3, 12: 2, 25: 2, 19: 3, 28: 1, 31: 3, 4: 2, 9: 3, 8: 1, 17: 2, 5: 4, 22: 2, 20: 1, 27: 1, 26: 1, 32: 1, 38: 1, 2: 4, 24: 1, 16: 1, 15: 1, 10: 1, 3: 1, 6: 1, 14: 1, 18: 1})
]
We can now know how many numbers are within a range by subtracting the values in the dictionary of one index, by the values in the dictionary of another:
i2 = 3
i1 = i2 - 3
num = 31
prev_count = prefix_counter[i2][num] - prefix_counter[i1][num]
print(prev_count) # 2
Another example:
i2 = data_keys.index('L19981120')
i1 = i2 - 9
num = 2
prev_count = prefix_counter[i2][num] - prefix_counter[i1][num]
print(prev_count) # 3
CodePudding user response:
Don't you have to sort the keys first?
from sortedcontainers import SortedDict
data = SortedDict(
{
"L19980909": [11, 12, 25],
"L19981013": [19, 28, 31],
"L19981016": [4, 9, 31],
"L19981020": [8, 11, 17],
"L19981023": [5, 22, 25],
"L19981027": [5, 20, 27],
"L19981030": [12, 19, 26],
"L19981105": [31, 32, 38],
"L19981109": [2, 22, 24],
"L19981110": [2, 16, 19],
"L19981113": [9, 15, 17],
"L19981119": [2, 10, 11],
"L19981120": [2, 3, 5],
"L19981126": [4, 6, 14],
"L19981127": [5, 9, 18],
"L19981201": [1, 6, 7],
}
)
for target_date, tlist in data.items():
# count previous occurances
counts = {}
for date, nlist in data.items():
if date == target_date:
break
for n in nlist:
if n in counts:
counts[n] = 1
else:
counts[n] = 1
for n in tlist:
if n not in counts:
counts[n] = 0
if counts[tlist[0]] counts[tlist[1]] counts[tlist[2]] > 0:
print(
target_date,
"$",
tlist,
"$",
counts[tlist[0]],
"$",
counts[tlist[1]],
"$",
counts[tlist[2]],
)
Produces:
L19981016 $ [4, 9, 31] $ 0 $ 0 $ 1
L19981020 $ [8, 11, 17] $ 0 $ 1 $ 0
L19981023 $ [5, 22, 25] $ 0 $ 0 $ 1
L19981027 $ [5, 20, 27] $ 1 $ 0 $ 0
L19981030 $ [12, 19, 26] $ 1 $ 1 $ 0
L19981105 $ [31, 32, 38] $ 2 $ 0 $ 0
L19981109 $ [2, 22, 24] $ 0 $ 1 $ 0
L19981110 $ [2, 16, 19] $ 1 $ 0 $ 2
L19981113 $ [9, 15, 17] $ 1 $ 0 $ 1
L19981119 $ [2, 10, 11] $ 2 $ 0 $ 2
L19981120 $ [2, 3, 5] $ 3 $ 0 $ 2
L19981126 $ [4, 6, 14] $ 1 $ 0 $ 0
L19981127 $ [5, 9, 18] $ 3 $ 2 $ 0
L19981201 $ [1, 6, 7] $ 0 $ 1 $ 0