Sorting the time format in shell script - linux

I have a file containing alerts occurence time. I want to sort those in ascending order. Can you please guide me about this.
Sample time format.
1 day, 19 hours
3 weeks
4 weeks, 1 day
2 minutes
1 month, 1 week
10 hours, 36 minutes
4 weeks, 1 day
4 weeks, 1 day
13 minutes
5 hours, 16 minutes
1 hour, 53 minutes
3 hours, 18 minutes
21 hours, 42 minutes
18 hours, 49 minutes
21 hours, 43 minutes

Maybe not super elegant, but straight forward in Python:
#!/usr/bin/env python
import operator
# 1 month = 28-31 days and 4 weeks = 28 days, so month is kept separate
time_in_seconds = {
'week': 7*24*60*60,
'day': 24*60*60,
'hour': 60*60,
'minute': 60,
'second': 1
}
if __name__ == '__main__':
times = []
with open('sample_time.txt', 'r') as f:
for line in f.read().split('\n'):
months = 0
seconds = 0
try:
for pair in line.split(', '):
num, denum = pair.split(' ')
if denum.startswith('month'):
months += int(num)
else:
seconds += time_in_seconds[denum.rstrip('s')]*int(num)
times.append([months, seconds, line])
except:
pass
sorted_times = sorted(times, key=operator.itemgetter(0,1))
for line in map(operator.itemgetter(2), sorted_times):
print(line)
It assumes your file is called sample_time.txt.

Related

convert string as 'hours' and 'mins' into minutes

I have a column in my dataframe df:
Time
2 hours 3 mins
5 hours 10 mins
1 hours 40 mins
10 mins
4 hours
6 hours 0 mins
I want to create a new column in df 'Minutes' that converts this column over to minutes
Minutes
123
310
100
10
240
360
Is there a python function to do this?
What I have tried is:
df['Minutes'] = pd.eval(
df['Time'].replace(['hours?', 'mins'], ['*60+', ''], regex=True))
Here is ugly bug pd.eval processing only less like 100 rows, so after stripping + is called pd.eval in Series.apply for prevent it:
df['Minutes'] = (df['Time'].replace(['hours?', 'mins'], ['*60+', ''], regex=True)
.str.strip('+')
.apply(pd.eval))
print (df)
Time Minutes
0 2 hours 3 mins 123
1 5 hours 10 mins 310
2 1 hours 40 mins 100
3 10 mins 10
4 4 hours 240
5 6 hours 0 mins 360
#verify for 120 rows
df = pd.concat([df] * 20, ignore_index=True)
df['Minutes1'] = pd.eval(
df['Time'].replace(['hours?', 'mins'], ['*60+', ''], regex=True).str.strip('+'))
print (df)
ValueError: unknown type object
Another solution with Series.str.extract and Series.add:
h = df['Time'].str.extract('(\d+)\s+hours').astype(float).mul(60)
m = df['Time'].str.extract('(\d+)\s+mins').astype(float)
df['Minutes'] = h.add(m, fill_value=0).astype(int)
print (df)
Time Minutes
0 2 hours 3 mins 123
1 5 hours 10 mins 310
2 1 hours 40 mins 100
3 10 mins 10
4 4 hours 240
5 6 hours 0 mins 360
jezrael's answer is excellent, but I spent quite some time working on this so i figured i'll post it.
You can use a regex to capture 'hours' and 'minutes' from your column, and then assign back to a new column after applying the logical mathematical operation to convert to minutes:
r = "(?:(\d+) hours ?)?(?:(\d+) mins)?"
hours = df.Time.str.extract(r)[0].astype(float).fillna(0) * 60
minutes = df.Time.str.extract(r)[1].astype(float).fillna(0)
df['minutes'] = hours + minutes
print(df)
Time minutes
0 2 hours 3 mins 123.0
1 5 hours 10 mins 310.0
2 1 hours 40 mins 100.0
3 10 mins 10.0
4 4 hours 240.0
5 6 hours 0 mins 360.0
I enjoy using https://regexr.com/ to test my regex

Python calendar with loops

days = int(input("Enter number of days: "))
day_of_week = input("The first day of the week: ")
print("{:>3}{:>3}{:>3}{:>3}{:>3}{:>3}{:>3}".format("S","M","T","W","Th","F","S"))
for d in range(1, days + 1):
print("{:3}".format(d),end="")
if (d % 7 == 0):
print()
Here's my output:
I'm confused... What should I add so that the first day of the week is my input's?
Below is one solution that actually uses the start day that you enter. You'll notice a couple of other improvements as well, specifically:
using an array of days for validation (I've made them match my sensibilities of two characters each but they'll work with the same entries you originally had);
using that same array for figuring out where the month should start;
also using it for simplifying the heading output;
validates the number of days to output;
adds a final newline output; and
uses f-strings for formatting (I prefer this because it localises the value to where it should be, rather than way out to the right somewhere in the format() parameter area, where you have to go searching for it).
The code is:
# Valid day list, adjust as necessary.
day_list = ["Su", "Mo", "Tu", "We", "Th", "Fr", "Sa"]
# Get days in month, with validation.
days = -1
while days < 1 or days > 31:
try:
days = int(input("Enter number of days: "))
if days < 28 or days > 31:
days = -1
except ValueError:
days = -1
# Get starting day, with validation.
start_day = ""
while start_day not in day_list:
start_day = input(f"The first day of the week ({', '.join(day_list)}): ")
# Output heading line.
for day in day_list:
print(f"{day:>3}", end="")
print()
# Pad with spaces in first week if needed.
start_pos = day_list.index(start_day)
for _ in range(start_pos):
print(" ", end="")
# Output each day, wrapping to new week if needed.
for day in range(1, days + 1):
if (start_pos != 0 and start_pos % 7 == 0):
print()
print(f"{day:3}", end="")
start_pos += 1
# Output final newline.
print()
A couple of sample runs:
Enter number of days: 27
Enter number of days: 32
Enter number of days: 28
The first day of the week (Su, Mo, Tu, We, Th, Fr, Sa): blah
The first day of the week (Su, Mo, Tu, We, Th, Fr, Sa): Mo
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6
7 8 9 10 11 12 13
14 15 16 17 18 19 20
21 22 23 24 25 26 27
28
Enter number of days: 30
The first day of the week (Su, Mo, Tu, We, Th, Fr, Sa): Su
Su Mo Tu We Th Fr Sa
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30
Enter number of days: 29
The first day of the week (Su, Mo, Tu, We, Th, Fr, Sa): Sa
Su Mo Tu We Th Fr Sa
1
2 3 4 5 6 7 8
9 10 11 12 13 14 15
16 17 18 19 20 21 22
23 24 25 26 27 28 29
days_of_week = ["S","M","T","W","Th","F","St"]
days = int(input("Enter number of days: "))
day_of_week = input("The first day of the week: ")
index = days_of_week.index(day_of_week)
new_days_of_week = days_of_week[index:]+days_of_week[:index]
print("{:>3}{:>3}{:>3}{:>3}{:>3}{:>3}{:>3}".format(*new_days_of_week))
for d in range(1, days + 1):
print("{:3}".format(d),end="")
if (d % 7 == 0):
print()
Output
Enter number of days: 31
The first day of the week: Th
Th F St S M T W
1 2 3 4 5 6 7
8 9 10 11 12 13 14
15 16 17 18 19 20 21
22 23 24 25 26 27 28
29 30 31

How to make a calendar in Python with a custom date range and custom start day of the month

I need to create a custom calendar, these are the days of the week=
Po Si Be Ri Ve An Ca Mi Fo Ar De Pr Sp Th Re
Next I need to find a way to fix the spacing so that it looks like a calendar.
Currently using a for statement with a range.
I also need to find out how to make the a new line after 15 numbers
# Create a function where you create the heading for the calendar
# Create input questions
import numpy as np
#dayofweek = input("What day of the week does the 1st day of the month start on? ")
numdays = int(input("How many days are there in the month? "))
#jubmonth = input("Is this a Jubilee Month ? ")
day = "Po Si Be Ri Ve An Ca Mi Fo Ar De Pr Sp Th Re"
print(day)
# Create a function where you create the list of numbers from 1 to x = numdays
x = numdays
y =range(1,x)
for elm in y:
print('',elm, end10=' ')
else:
print(elm, end=' ')
#print(dayofweek)
#print(numdays)
#print(jubmonth)
#print(y)
Not sure if i understood your requirement correctly but assuming you want a table style output for your calendar that will be evenly spaced you could use the below code. I have updated the code to cater for jubilee months
def print_cal(cal):
for line in cal:
print("".join([f'{str(item):>3s}' for item in line]))
while True:
# set up days , jubilee days, jubilee weeks
days = ['Po', 'Si', 'Be', 'Ri', 'Ve', 'An', 'Ca', 'Mi', 'Fo', 'Ar', 'De', 'Pr', 'Sp', 'Th', 'Re']
days_size = len(days)
jubilee_days = ['Be', 'An', 'Ca', 'Ar', 'De', 'Pr']
jubilee_week = [2, 3]
filler = '--'
# get user input
num_days = int(input("How many days are there in the month? "))
day_of_week = input("What day of the week does the 1st day of the month start on? ")
jub_month = input("Is it a Jub month (yes/no)? ").lower()
# work out which day to start on write our days as the first line then skip any days before our start day
day_index = days.index(day_of_week)
cal = [days]
cal.append(['' for _ in range(day_index)])
# now in a loop generate the days
for i in range(0, num_days):
# if the last list is full start a new one.
if len(cal[-1]) == days_size:
cal.append([])
#check for jub month
if jub_month == "yes" and len(cal) - 1 in jubilee_week:
#check for jub day and keep looping till its not a jub day
day = days[len(cal[-1])]
while day in jubilee_days:
cal[-1].append(filler)
day = days[len(cal[-1])]
#write the day to the last list
cal[-1].append(i + 1)
#print the cal
print_cal(cal)
again = input("Do you want to make another cal (yes/no)? ").lower()
if again != "yes":
break
OUTPUT
How many days are there in the month? 45
What day of the week does the 1st day of the month start on? Ve
Is it a Jub month (yes/no)? no
Po Si Be Ri Ve An Ca Mi Fo Ar De Pr Sp Th Re
1 2 3 4 5 6 7 8 9 10 11
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
27 28 29 30 31 32 33 34 35 36 37 38 39 40 41
42 43 44 45
Do you want to make another cal (yes/no)? yes
How many days are there in the month? 45
What day of the week does the 1st day of the month start on? Ve
Is it a Jub month (yes/no)? yes
Po Si Be Ri Ve An Ca Mi Fo Ar De Pr Sp Th Re
1 2 3 4 5 6 7 8 9 10 11
12 13 -- 14 15 -- -- 16 17 -- -- -- 18 19 20
21 22 -- 23 24 -- -- 25 26 -- -- -- 27 28 29
30 31 32 33 34 35 36 37 38 39 40 41 42 43 44
45
Do you want to make another cal (yes/no)? no
Process finished with exit code 0

Simple python program using while loops, off by one error

I have tried to figure out where the off by one error is and have had no luck. I am an absolute beginner at programming. The increase is supposed to start on year two, but my code adds it to year one. Thanks in advance for any and all help!
##
# salaryschedule.py
# 2/15/2017
# This program will calculate and print the salary schedule for years 1
# through 30 for the teachers in Murdock County. For each year of
# experience, up to 20 years, the salary is increased by 2%.
# Each year after 20, the salary stays the same as year 20.
##
RATE = 2.0
INITIAL_SALARY = 37238.00
salary = INITIAL_SALARY
year = 1
print("Murdock County")
print("Teacher Salary Schedule")
print()
print("Year Salary")
print("---- ------")
while year < 31 :
increase = salary * RATE / 100
salary = salary + increase
print("%4d %15.2f" % (year, salary))
year = year + 1
You only have to print the salary before increasing it.
RATE = 2.0
INITIAL_SALARY = 37238.00
salary = INITIAL_SALARY
year = 1
print("Murdock County")
print("Teacher Salary Schedule")
print()
print("Year Salary")
print("---- ------")
while year < 31 :
print("%4d %15.2f" % (year, salary))
increase = salary * RATE / 100
salary = salary + increase
year = year + 1
Output:
Murdock County
Teacher Salary Schedule
Year Salary
---- ------
1 37238.00
2 37982.76
3 38742.42
4 39517.26
5 40307.61
6 41113.76
7 41936.04
8 42774.76
9 43630.25
10 44502.86
11 45392.91
12 46300.77
13 47226.79
14 48171.32
15 49134.75
16 50117.45
17 51119.79
18 52142.19
19 53185.03
20 54248.73
21 55333.71
22 56440.38
23 57569.19
24 58720.57
25 59894.99
26 61092.89
27 62314.74
28 63561.04
29 64832.26
30 66128.90
Your while loop calculates the increase for the year, which is one, and then prints that. But you want to simply print year one as is, correct? So, the simple solution is just moving the print setting to the top of the loop. Year one will be calculated correctly, and then it will change the numbers of the salary and increase before restarting the loop. Like this:
while year < 31 :
print("%4d %15.2f" % (year, salary))
increase = salary * RATE / 100
salary = salary + increase
year = year + 1
Take note, that it will calculate the next salary/increase on the last loop, but not print it. Alternatively, add a print line before the loop that prints year one, such that the loop starts on year 2 (full code for second example):
RATE = 2.0
INITIAL_SALARY = 37238.00
salary = INITIAL_SALARY
year = 1
print("Murdock County")
print("Teacher Salary Schedule")
print()
print("Year Salary")
print("---- ------")
#Changed to so that salary does not increase after 20 years.
print("%4d %15.2f" % (year, salary))
while year < 31 :
if year < 20:
increase = salary * RATE / 100
salary = salary + increase
year = year + 1
print("%4d %15.2f" % (year, salary))
else:
year = year + 1
print("%4d %15.2f" % (year, salary))
Gives the output below, note that salary does is increased on year 20. If you do not want this, change the 20 in the if statement, to 19, so that it stops adding the increase one year earlier:
Murdock County
Teacher Salary Schedule
Year Salary
---- ------
1 37238.00
2 37982.76
3 38742.42
4 39517.26
5 40307.61
6 41113.76
7 41936.04
8 42774.76
9 43630.25
10 44502.86
11 45392.91
12 46300.77
13 47226.79
14 48171.32
15 49134.75
16 50117.45
17 51119.79
18 52142.19
19 53185.03
20 54248.73
21 54248.73
22 54248.73
23 54248.73
24 54248.73
25 54248.73
26 54248.73
27 54248.73
28 54248.73
29 54248.73
30 54248.73
31 54248.73

Binning values in Python3

Say I have the following txt file
Distances Counts
1 5
2 5
3 9
4 10
9 10
10 10
11 5
14 5
20 1
21 1
23 2
I would like a way to bin according to the first column and sum the second column.
The correct output if you use a bin of 5 would be
0-5 29
5-10 20
10-15 10
15-20 20
20-25 3
or just
5 29
10 20
15 10
20 20
25 3
i tried
binfile = open('distances.txt', 'r')
binsize = 5
summar = 0
binsize2 = binsize
for line in binfile:
line = line.strip().split('\t')
distance = int(line[0])
counts = int(line[1])
if distance <= binsize2:
summar += counts
else:
print(str(binsize2)+'\t'+str(summar))
binsize2 = binsize2 + binsize
summar = counts
but it doesn't print the last bin. Any suggestions?

Resources