So I have a list like this:
my_list = [{"id":21313,"remark":"","marks":"100"},
{"id":21314,"remark":"","marks":"29"},
{"id":21315,"remark":"","marks":"15"},
{"id":21316,"remark":"","marks":"50"},
{"id":21317,"remark":"","marks":"20"}]
The list have many elements. What I want to do is to iterate over the entire list,take a current element i as a point from which we check whether the marks of this point from the next two are more or less. If more than remark of good is made and if less than a remark of bad is made. This is what I want it to look like:
my_list = [{"id":21313,"remark":"good","marks":"100"},
{"id":21314,"remark":"bad","marks":"29"},
{"id":21315,"remark":"bad","marks":"15"},
{"id":21316,"remark":"NaN","marks":"50"},
{"id":21317,"remark":"NaN","marks":"20"}]
The last two are not available because there are not enough entries after them for comparison. Is there a way to do this?
You can make a slightly modified version of a sliding window iterator that also includes the last few elements:
from itertools import islice
def diminishing_window(seq, n=2):
"""
(s0, ..., s[n-1]), (s1, ..., sn), ..., (s[-2], s[-1]), (s[-1])
"""
it = iter(seq)
result = tuple(islice(it, n))
if len(result) == n:
yield result
for elem in it:
result = result[1:] + (elem,)
yield result
result = result[1:]
while result:
yield result
result = result[1:]
That will give you width n
"windows" over the data until the last few, which will get progressively smaller. If we consider the first item in those windows to be the item we're "on", then we can compare it to the other items in the window to determine its result.
def dict_replace(d, **kwargs):
res = d.copy()
res.update(kwargs)
return res
def get_remark(a, b):
if len(b) < 2:
return "NAN"
elif all(int(a["marks"]) > int(d["marks"]) for d in b):
return "good"
else:
return "bad"
new_list = [dict_replace(a, remark=get_remark(a, b)) for a, *b in diminishing_window(my_list, 3)]
print(new_list)
# [{'id': 21313, 'remark': 'good', 'marks': '100'}, {'id': 21314, 'remark': 'bad', 'marks': '29'},
# {'id': 21315, 'remark': 'bad', 'marks': '15'}, {'id': 21316, 'remark': 'NAN', 'marks': '50'},
# {'id': 21317, 'remark': 'NAN', 'marks': '20'}]
take a current element
i
as a point from which we check whether the marks of this point from the next two are more or less.
You can use zip_longest
to iterate in groups of 3 using a for
loop:
from itertools import zip_longest
# dictionary mapping for remark strings
rems = {1: 'good', 0: 'bad'}
for d1, d2, d3 in zip_longest(my_list, my_list[1:], my_list[2:], fillvalue={}):
if not (d2 and d3):
d1['remark'] = 'NaN'
else:
d1['remark'] = rems[int(d1['marks']) > max(int(d2['marks']), int(d3['marks']))]
print(my_list)
# [{'id': 21313, 'marks': '100', 'remark': 'good'},
# {'id': 21314, 'marks': '29', 'remark': 'bad'},
# {'id': 21315, 'marks': '15', 'remark': 'bad'},
# {'id': 21316, 'marks': '50', 'remark': 'NaN'},
# {'id': 21317, 'marks': '20', 'remark': 'NaN'}]
As an aside, you probably want to store these marks
as integers (or floats) rather than strings. This will avoid having to call int
each time for comparisons.
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.