Dict values incrementation in succession validation - python

I have a following task:
There is a dict like:
{1: datetime.date(2020, 7, 2), 2: datetime.date(2020, 7, 2), 11: datetime.date(2021, 7, 2)}
and it should follow one rule:
datetime object in value of each following element in dict should be >= than previous element ‘s value in dict after dict is sorted by keys. Result should be bool of whether this rule is violated or not.
Examples:
correct (each following date gte than previous one)
{1: datetime.date(2020, 7, 2), 2: datetime.date(2020, 7, 2), 11: datetime.date(2021, 7, 2)}
incorrect (2017 < than 2020 in previous element)
{1: datetime.date(2020, 7, 2), 2: datetime.date(2020, 7, 2), 11: datetime.date(2017, 7, 2)}
What I do to validate proper order:
import more_itertools
# sort dict by keys
sorted_by_keys_numbers = dict(sorted(original_dict.items()))
# check if rule is violated or not
are_dates_sorted = more_itertools.is_sorted(sorted_by_keys_numbers .values())
# returns True or False
But it heavily function based and non-pythonic
Is it any alternative, that are:
Pythonic
2)Non massive with multiple levels of nested FOR, IF, etc
Thank you
P>S Python 3.8, so all element are mantain order

I would try something like this with an expression generator and a zip on two list built from dictionary value
from datetime import datetime
data = {1: datetime(2020, 7, 2),
2: datetime(2020, 7, 2),
11: datetime(2021, 7, 4)}
res = all(i <= j for i, j in zip(list(data.values()), list(data.values())[1:]))

Related

Get top 5 max reoccurring values in a Python list? [duplicate]

This question already has answers here:
How to find most common elements of a list? [duplicate]
(11 answers)
How do I count the occurrences of a list item?
(29 answers)
Closed 4 years ago.
Let's say I have a list like so:
list = [0,0,1,1,1,1,1,1,1,1,3,3,3,3,5,9,9,9,9,9,9,22,22,22,22,22,22,22,22,22,22,45]
The top 5 reoccurring values would be:
22, 1, 9, 3, and 0.
What is the best way to get these values, as well as the number of times they reoccur? I was thinking of pushing the values into a new list, so that I get something like:
new_list = [22,10, 1,8, 9,6, 3,4, 0,2]
With the list value being the odd index entry, and the reoccurred value being the even index entry.
EDIT: What is the simplest way to do this without using a library?
Use collections.Counter:
from collections import Counter
l = [0,0,1,1,1,1,1,1,1,1,3,3,3,3,5,9,9,9,9,9,9,22,22,22,22,22,22,22,22,22,22,45]
print(Counter(l).most_common())
[(22, 10), (1, 8), (9, 6), (3, 4), (0, 2), (5, 1), (45, 1)]
You feed it an iterable and it counts it for you. The resultings dictionaries key is the value that was counted, its value is how often it occured. (i.e. 22 was counted 10 times)
Doku: collections.Counter(iterable)
Sidenote:
dont call variables after types or built ins, you shadow them and get problems later. Never call anything
list, tuple, dict, set, max, min, abs, ...
See: https://docs.python.org/3/library/functions.html
Use collections.Counter from the standard library.
import collections
list = [0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 3, 3, 3, 3, 5, 9, 9, 9, 9, 9, 9, 22, 22, 22, 22, 22, 22, 22, 22, 22, 22, 45]
ctr = collections.Counter(list)
print(ctr.most_common(5))
outputs
[
(22, 10),
(1, 8),
(9, 6),
(3, 4),
(0, 2),
]

Testing if a value is in either one of two lists

I have one area in my code that checks if item of one list is in other two lists and return a result depending on that.
Apparently, first IF clause is always true and only result from that clause is returned.
Here is the example:
from datetime import date
days = [date(2018, 9, 10), date(2018, 9, 11), date(2018, 9, 12)]
list_one = [date(2018, 9, 13), date(2018, 9, 14), date(2018, 9, 15)]
list_two = [date(2018, 9, 8), date(2018, 9, 9), date(2018, 9, 10)]
for day in days:
if day not in(list_one, list_two):
print('Case one')
elif day in list_one:
print('Case two')
elif day in list_two:
print('Case three')
(list_one, list_two) is a tuple of exactly two elements, containing list_one and list_two. Since a day is never equal to a list, day not in (list_one, list_two) turns out to be True.
You could either merge the lists and write
lists = list_one + list_two
if day not in lists:
...
or use
if day not in list_one and day not in list_two:
...
or alternatively, applying De Morgan's laws:
if not (day in list_one or day in list_two):
...
to express that day is in neither of those lists.
Change the first if to
if day not in list_one + list_two
Currently you don't have a list of elements, you have a tuple of two lists. So, to be in it, the element has to be one of those lists.
from datetime import date
days = [date(2018, 9, 10), date(2018, 9, 11), date(2018, 9, 12)]
list_one = [date(2018, 9, 13), date(2018, 9, 14), date(2018, 9, 15)]
list_two = [date(2018, 9, 8), date(2018, 9, 9), date(2018, 9, 10)]
for day in days:
if (day not in list_one and day not in list_two):
print('Case one')
elif day in list_one:
print('Case two')
elif day in list_two:
print('Case three')
Since you already have two if blocks testing if day is in either lists, for your purpose it's a easier (and more efficient) to simply use the else block for the case where day is in neither lists:
if day in list_one:
print('Case two')
elif day in list_two:
print('Case three')
else:
print('Case one')
Or any, to check if any elements are true, iterate trough the two list [list_one,list_two] if one of them are it will be true because using in will declare a Boolean statement:
...
if any(day in i for i in [list_one,list_two]):
...
...

Python: file oldest date value in a list of objects

While I understand that you can get the oldest date in a list of dates by using min(list_of_dates), say I have have a list of dictionaries which contain arbitrary keys that have date values:
[{key1: date1}, {key2: date2}, {key3: date3}]
Is there a built-in method to return the dictionary with the oldest date value? Do I need to iterate over the list, and if so what would that look like?
You can get the minimum date value per dictionary:
min(list_of_dictionaries, key=lambda d: min(d.values()))
This would work with just 1 or with multiple values per dictionary in the list, provided they are all date objects.
Demo:
>>> from datetime import date
>>> import random, string
>>> def random_date(): return date.fromordinal(random.randint(730000, 740000))
...
>>> def random_key(): return ''.join([random.choice(string.ascii_lowercase) for _ in range(10)])
...
>>> list_of_dictionaries = [{random_key(): random_date() for _ in range(random.randint(1, 3))} for _ in range(5)]
>>> list_of_dictionaries
[{'vsiaffoloi': datetime.date(2018, 1, 3)}, {'omvhscpvqg': datetime.date(2020, 10, 7), 'zyvrtvptuw': datetime.date(2001, 7, 25), 'hvcjgsiicz': datetime.date(2019, 11, 30)}, {'eoltbkssmj': datetime.date(2016, 2, 27), 'xqflazzvyv': datetime.date(2024, 9, 1), 'qaszxzxbsg': datetime.date(2014, 11, 26)}, {'noydyjtmjf': datetime.date(2013, 6, 4), 'okieejoiay': datetime.date(2020, 12, 15), 'ddcqoxkpdn': datetime.date(2002, 7, 13)}, {'vbwstackcq': datetime.date(2025, 12, 14)}]
>>> min(list_of_dictionaries, key=lambda d: min(d.values()))
{'omvhscpvqg': datetime.date(2020, 10, 7), 'zyvrtvptuw': datetime.date(2001, 7, 25), 'hvcjgsiicz': datetime.date(2019, 11, 30)}
or just one value per dictionary:
>>> list_of_dictionaries = [{random_key(): random_date()} for _ in range(5)]
>>> list_of_dictionaries
[{'vmlrfbyybp': datetime.date(2001, 10, 25)}, {'tvenffnapv': datetime.date(2003, 1, 1)}, {'ivypocbyuz': datetime.date(2026, 8, 9)}, {'trywaosiqm': datetime.date(2022, 7, 29)}, {'ndqmejmfqj': datetime.date(2001, 2, 13)}]
>>> min(list_of_dictionaries, key=lambda d: min(d.values()))
{'ndqmejmfqj': datetime.date(2001, 2, 13)}
Per the official docs, min supports an arbitrary key function to specify what to compare on. If you require more specific behavior, you may also consider sorted instead.

Value difference comparison within a list in python

I have a nested list that contains different variables in it. I am trying to check the difference value between two consecutive items, where if a condition match, group these items together.
i.e.
Item 1 happened on 1-6-2012 1 pm
Item 2 happened on 1-6-2012 4 pm
Item 3 happened on 1-6-2012 6 pm
Item 4 happened on 3-6-2012 5 pm
Item 5 happened on 5-6-2012 5 pm
I want to group the items that have gaps less than 24 Hours. In this case, Items 1, 2 and 3 belong to a group, Item 4 belong to a group and Item 5 belong to another group. I tried the following code:
Time = []
All_Traps = []
Traps = []
Dic_Traps = defaultdict(list)
Traps_CSV = csv.reader(open("D:/Users/d774911/Desktop/Telstra Internship/Working files/Traps_Generic_Features.csv"))
for rows in Traps_CSV:
All_Traps.append(rows)
All_Traps.sort(key=lambda x: x[9])
for length in xrange(len(All_Traps)):
if length == (len(All_Traps) - 1):
break
Node_Name_1 = All_Traps[length][2]
Node_Name_2 = All_Traps[length + 1][2]
Event_Type_1 = All_Traps[length][5]
Event_Type_2 = All_Traps[length + 1][5]
Time_1 = All_Traps[length][9]
Time_2 = All_Traps[length + 1][9]
Difference = datetime.strptime(Time_2[0:19], '%Y-%m-%dT%H:%M:%S') - datetime.strptime(Time_1[0:19], '%Y-%m-%dT%H:%M:%S')
if Node_Name_1 == Node_Name_2 and \
Event_Type_1 == Event_Type_2 and \
float(Difference.seconds) / (60*60) < 24:
Dic_Traps[length].append(All_Traps[Length])
But I am missing some items. Ideas?
For sorted list you may use groupby. Here is a simplified example (you should convert your date strings to datetime objects), it should give the main idea:
from itertools import groupby
import datetime
SRC_DATA = [
(1, datetime.datetime(2015, 06, 20, 1)),
(2, datetime.datetime(2015, 06, 20, 4)),
(3, datetime.datetime(2015, 06, 20, 5)),
(4, datetime.datetime(2015, 06, 21, 1)),
(5, datetime.datetime(2015, 06, 22, 1)),
(6, datetime.datetime(2015, 06, 22, 4)),
]
for group_date, group in groupby(SRC_DATA, key=lambda X: X[1].date()):
print "Group {}: {}".format(group_date, list(group))
Output:
$ python python_groupby.py
Group 2015-06-20: [(1, datetime.datetime(2015, 6, 20, 1, 0)), (2, datetime.datetime(2015, 6, 20, 4, 0)), (3, datetime.datetime(2015, 6, 20, 5, 0))]
Group 2015-06-21: [(4, datetime.datetime(2015, 6, 21, 1, 0))]
Group 2015-06-22: [(5, datetime.datetime(2015, 6, 22, 1, 0)), (6, datetime.datetime(2015, 6, 22, 4, 0))]
First of all, change those horrible cased variable names. Python has its own convention of naming variables, classes, methods and so on. It's called snake case.
Now, on to what you need to do:
import datetime as dt
import pprint
ts_dict = {}
with open('timex.dat', 'r+') as f:
for line in f.read().splitlines():
if line:
item = line.split('happened')[0].strip().split(' ')[1]
timestamp_string = line.split('on')[-1].split('pm')[0]
datetime_stamp = dt.datetime.strptime(timestamp_string.strip(), "%d-%m-%Y %H")
ts_dict[item] = datetime_stamp
This is a hackish way of giving you this:
item_timestamp_dict= {
'1': datetime.datetime(2012, 6, 1, 1, 0),
'2': datetime.datetime(2012, 6, 1, 4, 0),
'3': datetime.datetime(2012, 6, 1, 6, 0),
'4': datetime.datetime(2012, 6, 3, 5, 0),
'5': datetime.datetime(2012, 6, 5, 5, 0)}
A dictionary of item # as key, and their datetime timestamp as value.
You can use the datetime timestamp values' item_timestamp_dict['1'].hour values to do your calculation.
EDIT: It can be optimized a lot.

Change multiple keys from dictionary, while doing timedelta operation in Python

I have a dictionary, which the keys are integers. I arbitrarily changed one of the keys to a date, and I need to change the other keys.
Sample data:
{'C-STD-B&M-SUM': {datetime.date(2015, 7, 12): 0,
-1: 0.21484699999999998,
-2: 0.245074,
-3: 0.27874}
Expected output:
{'C-STD-B&M-SUM': {datetime.date(2015, 7, 12): 0,
datetime.date(2015, 7, 11): 0.21484699999999998,
datetime.date(2015, 7, 10): 0.245074,
datetime.date(2015, 7, 9): 0.27874}
Current code so far:
def change_start_date(dictionary_with_temporal_distribution):
unsw_mid_year_end_date = datetime.date(2015, 7, 12)
dictionary_with_temporal_distribution['C-STD-B&M-SUM'][unsw_mid_year_end_date] = dictionary_with_temporal_distribution['C-STD-B&M-SUM'][0]
del dictionary_with_temporal_distribution['C-STD-B&M-SUM'][0]
for k, v in dictionary_with_temporal_distribution['C-STD-B&M-SUM'].items():
You can try something like -
def change_start_date(dictionary_with_temporal_distribution):
unsw_mid_year_end_date = datetime.date(2015, 7, 12)
for k in list(dictionary_with_temporal_distribution['C-STD-B&M-SUM'].keys()):
dictionary_with_temporal_distribution['C-STD-B&M-SUM'][unsw_mid_year_end_date + timedelta(days=k)] = dictionary_with_temporal_distribution['C-STD-B&M-SUM'][k]
del dictionary_with_temporal_distribution['C-STD-B&M-SUM'][k]
You can use dict comprehension syntax and transform and replace the keys:
dct = {datetime.date(2015, 7, 12): 0,
-1: 0.21484699999999998,
-2: 0.245074,
-3: 0.27874}
def offset(offset, base):
"""Applies an offset in days to a base date.
If the offset is already a date it is returned as is."""
if type(offset) == datetime.date:
return offset
return base + datetime.timedelta(offset)
def offset_keys(dct, base):
"""Takes a dict and runs offset(key, base) on all keys"""
return { offset(k, base): v for k, v in dct.items() }
pprint(offset_keys(dct, datetime.date(2015, 7, 12)))
{datetime.date(2015, 7, 9): 0.27874,
datetime.date(2015, 7, 10): 0.245074,
datetime.date(2015, 7, 11): 0.21484699999999998,
datetime.date(2015, 7, 12): 0}

Categories

Resources