def main():
rain = [] # empty list awaiting user input
MONTH = ["January", "February"] # parallel to the rain?
SIZE = 2 # array size
getRain(rain,SIZE) # ask user to input each month rainfall amount
highest = findHigh(rain, SIZE, MONTH)
displayValues(SIZE, highest, rain)
# get input and add to list
def getRain(rain, SIZE):
index = 0
while (index <= SIZE - 1):
print('Enter rainfall for month', index + 1)
rainInput = int(input('Enter rainfall: '))
rain.append(rainInput)
index = index + 1
# finding the highest value in the array and printing the highest value with month
def findHigh(rain, SIZE, MONTH):
highest = rain[0]
index = 1
while (index <= SIZE - 1):
if (rain[index] > highest):
highest = rain[index]
else:
index = index + 1
print("The highest month is:", MONTH[index - 1]) # not too sure if I need this here
return highest
# display the values
def displayValues(SIZE, highest, rain):
print("--------------------------------")
print("The highest value is:", highest)
# run code
main()
Hi, I am trying to figure out how to get it so then my output would print the right month in correlation to the amount of rainfall each month has (for example: january has 50 and february has 40)
Output: The highest month is: January
I've tried making another condition thing or another module to try to check the values, but I cannot compare strings to int in the list. I have also tried moving the print values but I feel like another module would be needed to find the right month unless I am just printing it in the wrong area
If you don't want to change the rest of the code, you can modify findHigh to track and print the month with the highest value:
def findHigh(rain, SIZE, MONTH):
highest = 0
index = 1
while (index <= SIZE - 1):
if (rain[index] > rain[highest]):
highest = index
else:
index = index + 1
print("The highest month is:", MONTH[highest]) # not too sure if I need this here
return rain[highest]
or slightly more pythonic:
def findHigh(rain, SIZE, MONTH):
highest = 0
for index in range(SIZE):
if rain[index] > rain[highest]:
highest = index
print("The highest month is:", MONTH[highest]) # not too sure if I need this here
return rain[highest]
It may be better to move both the prints to displayValues:
def main():
rain = [] # empty list awaiting user input
MONTH = ["January", "February"] # parallel to the rain?
SIZE = 2 # array size
getRain(rain,SIZE) # ask user to input each month rainfall amount
highest = findHigh(rain, SIZE)
displayValues(SIZE, highest, rain, MONTH)
# get input and add to list
def getRain(rain, SIZE):
index = 0
while (index <= SIZE - 1):
print('Enter rainfall for month', index + 1)
rainInput = int(input('Enter rainfall: '))
rain.append(rainInput)
index = index + 1
# finding the highest value in the array and printing the highest value with month
def findHigh(rain, SIZE):
highest = 0
for index in range(SIZE):
if rain[index] > rain[highest]:
highest = index
return highest
# display the values
def displayValues(SIZE, highest, rain, MONTH):
print("The highest month is:", MONTH[highest]) # not too sure if I need this here
print("--------------------------------")
print("The highest value is:", rain[highest])
I have two list(oil_price and price, both the same length) and want it to iterate through both loops and go through the if-else statements. The code only goes does the first row. Can anyone help?
for x in oil_price:
for y in price:
if float(x) <= 60:
cost = y * qty
if cost > funds:
return funds, stocks
else:
cash_balance = float(funds - cost)
stocks += qty
return cash_balance, stocks
elif float(x) > 60:
sale = qty * y
if qty > stocks:
return funds, stocks
else:
cash_balance = float(funds + sale)
stocks_owned = stocks - qty
return cash_balance, stocks_owned
To add to Błotosmętek's answer (use of a return statement exits the function after the first iteration of the loop) , you could use a list of lists (2D-list/array, if you will) to store the intermediate results, then use continue to go to the next step of the loop. This way, you calculate the results for all combinations of oil_price and price.
So, it could look something like this:
results = []
for x in oil_price:
for y in price:
if float(x) <= 60:
cost = y * qty
if cost > funds:
results.append([funds, stocks])
continue
else:
cash_balance = float(funds - cost)
stocks += qty
results.append([cash_balance, stocks])
continue
elif float(x) > 60:
sale = qty * y
if qty > stocks:
results.append([funds, stocks])
continue
else:
cash_balance = float(funds + sale)
stocks_owned = stocks - qty
results.append([cash_balance, stocks_owned])
continue
I'm sure this could look a lot prettier, but it should work nonetheless.
I'm trying to extract climate data from various .nc files I have but the process is taking extremely long, I suspect it has something to do with the fact that I'm trying to extract the data for every day of June, July, August for the next 79 years. But I'm a novice programmer and I realize there might've been a few oversights by me (efficiency wise) that might've resulted in a slightly better performance.
This is the snippet
def calculateTemp(coords, year, model):
"""
takes in all coordinates of a line between two grid stations and the year
converts the year into date
takes average of temperature of each day of the month of June for each
coordinate and then takes average of all coordinates to find average temp
for that line for the month of June
"""
print(year)
# coords represents a list of different sets of coordinates between two grids
temp3 = 0 # sum of all temps of all coordinates
for i in range(0, len(coords)):
temp2 = 0
counter = 0
# this loop represents that the 15 years data is being extracted for
# each coordinate set and average of those 15 years is being taken
for p in range(0, 15):
temp1 = 0 # sum of all temps for one coordinate in all days of June, tuly, august
if year+ p < 100:
# this loop represents the months of jun, jul, aug
for j in range(6, 9):
# 30 days of each month
for k in range(1, 31):
if k < 10:
# this if-else makes a string of date
date = '20'+str(year+p)+'-0'+str(j)+'-0'+str(k)
else:
date = '20'+str(year+p)+'-0'+str(j)+'-'+str(k)
# there are 3 variants of the climate model
# for years upto 2040, between 2041-2070
# and between 2071 and 2099
# hence this if else block
if year+p < 41:
temp1 += model[0]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
elif year+p >= 41 and year+p <71:
temp1 += model[1]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
else:
temp1 += model[2]['tasmax'].sel(
lon=coords[i][1], lat=coords[i][0], time=date, method='nearest').data[0]
counter += 1
avg = temp1/(len(range(0,30))*len(range(6,9)))
temp2 += avg
temp3 += temp2/counter
Tamb = temp3/len(coords)
return Tamb
Is there anyway I can increase the performance of this code and optimize it?
I just replaced the innermost loops k in range(1,31)and j in range(6,9)into a dict comprehension to generate all the dates and corresponding value from your model. Then simply averaged these values for every value of p and then for every coord in coords.
Give this a shot. Dicts should make the processing faster. Also check if the averages are exactly how you are calculating them in your function.
def build_date(year,p,j,k):
return '20'+str(year+p)+'-0'+str(j)+'-0'+str(k) if k<10 else '20'+str(year+p)+'-0'+str(j)+'-'+str(k)
def calculateTemp(coords, year, model):
func2 = lambda x,date:model[x]['tasmax'].sel(lon=coords[i][1],
lat=coords[i][0],
time=date,
method='nearest').data[0]
print(year)
out = {}
for i in range(len(coords)):
inner = {}
for p in range(0,15):
if year + p < 100:
dates = {build_date(year,p,j,k):func2(0,build_date(year,p,j,k)) if year+p<41 \
else func2(1,build_date(year,p,j,k)) if (year+p >= 41 and year+p <71) \
else func2(2,build_date(year,p,j,k))
for j in range(6,9) \
for k in range(1,31) }
inner[p] = sum([v for k,v in dates.items()])/len(dates)
out[i] = inner
coord_averages = {k : sum(v.values())/len(v) for k,v in out.items() }
Tamb = sum([v for k,v in coord_averages.items()])/len(coord_averages)
return Tamb
So I this code which is suppose to return a list with the closest leap year of a list of years.
For example: calling the function with [1995 1750 2018] should return
1996 1748 2016
Which it does for that set of numbers.
The problem I am having is that when a leap year is in the input for example 2008 it does not give me back the closest leap year to 2008. I get back 2008.
Any suggestions as to how I can modify the code to make it work?
code
def is_leap(year):
leap = False
if year % 4 == 0:
if year % 100 != 0 or year % 400 == 0:
leap = True
return leap
major_b = []
major_f = []
newLst = []
def year_forward(yearBounds):
for item in yearBounds:
counter = 0
while not is_leap(item):
item = item + 1
counter += 1
major_f.append([item, counter])
return major_f
def year_backward(yearBounds):
for item in yearBounds:
counter = 0
while not is_leap(item):
item = item - 1
counter -= 1
major_b.append([item,counter])
return major_b
def findLastLeapYears(yearBounds):
forward = year_forward(yearBounds)
backward = year_backward(yearBounds)
counter = 0
for item in forward:
if abs(item[1]) < abs(backward[counter][1]):
newLst.append (str(item[0]))
counter+=1
elif abs(item[1]) == abs(backward[counter][1]):
if item[0] < backward[counter][0]:
newLst.append (str(item[0]))
counter += 1
else:
newLst.append (str(backward[counter][0]))
counter += 1
else:
newLst.append (str(backward[counter][0]))
counter+=1
return newLst
I'd avoid trying to roll your own leap year detection code. Use calendar.isleap to determine whether a year is a leap year or not.
Then go in a loop, like this:
import calendar
def find_nearest_leap(year):
offset = 1
while True:
if calendar.isleap(year - offset):
return year - offset
if calendar.isleap(year + offset):
return year + offset
offset += 1
To find the list of nearest leap years for a list of values, do this:
nearest_leap_years = [find_nearest_leap(year) for year in years]
Where years is the list of years you are interested in.
I'm also assuming the nearest leap year isn't the year itself, which seems to be a constraint of the problem...
Given a list of people with their birth and end years (all between 1900 and 2000), find the year with the most number of people alive.
Here is my somewhat brute-force solution:
def most_populated(population, single=True):
years = dict()
for person in population:
for year in xrange(person[0], person[1]):
if year in years:
years[year] += 1
else:
years[year] = 0
return max(years, key=years.get) if single else \
[key for key, val in years.iteritems() if val == max(years.values())]
print most_populated([(1920, 1939), (1911, 1944),
(1920, 1955), (1938, 1939)])
print most_populated([(1920, 1939), (1911, 1944),
(1920, 1955), (1938, 1939), (1937, 1940)], False)
I'm trying to find a more efficient way to solve this problem in Python. Both - readability and efficiency counts. Moreover, for some reason my code won't print [1938, 1939] while it should.
Update
Input is a list of tuples, where first element of a tuple is a year when person was born, and second element of a tuple is the year of death.
Update 2
End year (2nd part of tuple) counts as well as a year of the person being alive (so If the person dies in Sept 1939 (we don't care about the month), he is actually alive in 1939, at least part of it). That should fix the 1939' missing in results.
Best solution?
While readability counts in favor of #joran-beasley, for bigger input most efficient algorithm was provided by #njzk2. Thanks #hannes-ovrén for providing analysis in IPython notebook on Gist
Another solution I just though of:
Create 2 tables, birthdates and deathdates.
Accumulate birth dates and death dates in those tables.
Browse those tables to accumulate the number of alive people at the time.
Grand total complexity is O(n)
Implementation
from collections import Counter
def most_populated(population, single=True):
birth = map(lambda x: x[0], population)
death = map(lambda x: x[1] + 1, population)
b = Counter(birth)
d = Counter(death)
alive = 0
years = {}
for year in range(min(birth), max(death) + 1):
alive = alive + b[year] - d[year]
years[year] = alive
return max(years, key=years.get) if single else \
[key for key, val in years.iteritems() if val == max(years.values())]
Better
from collections import Counter
from itertools import accumulate
import operator
def most_populated(population, single=True):
delta = Counter(x[0] for x in population)
delta.subtract(Counter(x[1]+1 for x in population))
start, end = min(delta.keys()), max(delta.keys())
years = list(accumulate(delta[year] for year in range(start, end)))
return max(enumerate(years), key=operator.itemgetter(1))[0] + start if single else \
[i + start for i, val in enumerate(years) if val == max(years)]
>>> from collections import Counter
>>> from itertools import chain
>>> def most_pop(pop):
... pop_flat = chain.from_iterable(range(i,j+1) for i,j in pop)
... return Counter(pop_flat).most_common()
...
>>> most_pop([(1920, 1939), (1911, 1944), (1920, 1955), (1938, 1939)])[0]
I would go like this:
Sort persons by birth year (unborn list)
Starting from the first born
Put that person in the alive list
Using an insertion sort by date of death (the list stays sorted, so use a binary search)
Until you reach a person that was not born that year
Then, starting from the person in the alive list that dies first, remove it from the list.
Put the size of the alive list in a dict
Increment the year
Loop until the unborn and alive lists are empty
Complexity should be around O((m + n) * log(m)) (each year is considered only once, and each person only twice, multiplied by the insertion cost in the alive list)
Implementation
from bisect import insort
def most_populated(population, single=True):
years = dict()
unborn = sorted(population, key=lambda x: -x[0])
alive = []
dead = []
for year in range(unborn[-1][0], max(population, key=lambda x: x[1])[1] + 1):
while unborn and unborn[-1][0] == year:
insort(alive, -unborn.pop()[1])
while alive and alive[-1] == -(year - 1):
dead.append(-alive.pop())
years[year] = len(alive)
return max(years, key=years.get) if single else \
[key for key, val in years.iteritems() if val == max(years.values())]
We can also use numpy slicing, which is quite neat, and should also be quite efficient:
import numpy as np
from collections import namedtuple
Person = namedtuple('Person', ('birth', 'death'))
people = [Person(1900,2000), Person(1950,1960), Person(1955, 1959)]
START_YEAR = 1900
END_YEAR = 2000
people_alive = np.zeros(END_YEAR - START_YEAR + 1) # Alive each year
for p in people:
a = p.birth - START_YEAR
b = p.death - START_YEAR + 1 # include year of death
people_alive[a:b] += 1
# Find indexes of maximum aliveness and convert to year
most_alive = np.flatnonzero(people_alive == people_alive.max()) + START_YEAR
EDIT It seems like the namedtuple adds a bit of overhead, so to speed up a bit more, remove the namedtuple and do
for birth, death in people: instead.
Just put the birth and death years into a dict. If it is birth, increase the value by 1. or vice versa.
Sort the dict by keys and iterate by reading the current number of the alive people.
Follow the 'maxAlive' an 'theYear' to get the first year with the highest number
years = {}
for p in people:
if p.birth in years:
years[p.birth] += 1
else:
years[p.birth] = 1
if p.death in years:
years[p.death] -= 1
else:
years[p.death] = -1
alive = 0
maxAlive = 0
theYear = people[0].birth
for year in sorted(years):
alive += years[year]
if alive > maxAlive:
maxAlive = alive
theYear = year
Without importing anything, and using a class for readability, here's my solution. Let me know what you think! I also made a separate function for getMaxBirthYear in case you're at an interview and someone wants you to code that out rather than using built in functions (I used them :) )
class Person:
def __init__(self, birth=None, death=None):
self.birth=birth
self.death=death
def getPopulationPeak(people):
maxBirthYear = getMaxBirthYear(people)
deltas = getDeltas(people, maxBirthYear)
currentSum = 0
maxSum = 0
maxYear = 0
for year in sorted(deltas.keys()):
currentSum += deltas[year]
if currentSum > maxSum:
maxSum = currentSum
maxYear = year
return maxYear, maxSum
def getMaxBirthYear(people):
return max(people, key=lambda x: x.birth).birth
def getDeltas(people, maxBirthYear):
deltas = dict()
for person in people:
if person.birth in deltas.keys():
deltas[person.birth] += 1
else:
deltas[person.birth] = 1
if person.death + 1 in deltas.keys():
deltas[person.death + 1] -= 1
elif person.death + 1 not in deltas.keys() and person.death <= maxBirthYear: # We can skip deaths after the last birth year
deltas[person.death + 1] = -1
return deltas
testPeople = [
Person(1750,1802),
Person(2000,2010),
Person(1645,1760),
Person(1985,2002),
Person(2000,2050),
Person(2005,2080),
]
print(getPopulationPeak(testPeople))
How about this one:
def max_pop(pop):
p = 0; max = (0,0)
for y,i in sorted(chain.from_iterable([((b,1), (d+1,-1)) for b,d in pop])):
p += i
if p > max[1]: max=(y,p)
return max
It's not affected by the year span but is nlogn in the |pop| (unless you'd roll out a radix sort which would be ~ 10n for a thousand year span and should be faster for |pop|>1000 ). Can't have both. A very general solution would have to scan first and decide which algo to use based on measured year span and |pop|.
my answer
import java.util.LinkedHashMap;
import java.util.LinkedList;
import java.util.List;
import java.util.Map;
public class AlogrimVarsta {
public static void main(String args[]) {
int startYear = 1890;
int stopYear = 2000;
List<Person> listPerson = new LinkedList<>();
listPerson.add(new Person(1910, 1940));
listPerson.add(new Person(1920, 1935));
listPerson.add(new Person(1900, 1950));
listPerson.add(new Person(1890, 1920));
listPerson.add(new Person(1890, 2000));
listPerson.add(new Person(1945, 2000));
Map<Integer, Integer> mapPersoaneCareAuTrait = new LinkedHashMap<>();
for (int x = startYear; x <= stopYear; x++) {
mapPersoaneCareAuTrait.put(x, 0);
}
for (int x = startYear; x <= stopYear; x++) {
for (Person per : listPerson) {
int value = mapPersoaneCareAuTrait.get(x);
if (per.getBorn() == x) {
mapPersoaneCareAuTrait.put(x, value + 1);
continue;
}
if (per.getDie() == x) {
mapPersoaneCareAuTrait.put(x, value + 1);
continue;
}
if ((per.getDie() - per.getBorn() > per.getDie() - x) && (per.getDie() - x > 0)) {
mapPersoaneCareAuTrait.put(x, value + 1);
continue;
}
}
}
for (Map.Entry<Integer, Integer> mapEntry : mapPersoaneCareAuTrait.entrySet()) {
System.out.println("an " + mapEntry.getKey() + " numar " + mapEntry.getValue());
}
}
static class Person {
final private int born;
final private int die;
public Person(int pBorn, int pDie) {
die = pDie;
born = pBorn;
}
public int getBorn() {
return born;
}
public int getDie() {
return die;
}
}
}
l = [(1920, 1939), (1911, 1944),(1920, 1955), (1938, 1939)]
union = set({})
for i in l:
temp = set(range(min(i), max(i) + 1))
if len(union) == 0:
union = temp
union = temp & union
print(union)
I came over the following code that is exactly what you need.
Let's say the range of years is 1900 - 2000
Steps of the algorithm
Construct an array X of 100 integers (all initialized to zero; 101 integers if the year 2000 is included).
For each of the N people, increment X[birth year - 1900] by one and decrement X[death year - 1900] by one.
Iterate through X, maintaining a sum of each element as you go. The year with the most people alive is 1900 plus the index where the sum is maximum.
Code (Python as requested)
def year_with_max_population(people):
population_changes = [0 for _ in xrange(1900, 2000)]
for person in people:
population_changes[person.birth_year - 1900] += 1
population_changes[person.death_year - 1900] -= 1
max_population = 0
max_population_index = 0
population = 0
for index, population_change in enumerate(population_changes):
population += population_change
if population > max_population:
max_population = population
max_population_index = index
return 1900 + max_population_index
credit 'Brian Schmitz' here