This is the repo containing my code for the reddit programming challenge (to be sent as an application for hire)

reddit.py 4.8KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117
  1. # Lily Carpenter
  2. # lily-redditchallenge@azrazalea.net
  3. # 2049 South Florence Apt. 8
  4. # Springfield, MO
  5. # 417-379-3326
  6. #
  7. # Premise:
  8. # While I'm sure there is a fancy algorithm to do this very efficiently, I have not gotten far enough into
  9. # math/computer science theory in order to be able to come up with it effectively.
  10. #
  11. # Therefore, here is how my script works:
  12. # 1. Sorts all panels in descending order based on value
  13. # 2. Starting with the person with the highest yield (me) and going from there
  14. # it adds the highest value panels to the set panel list until we reach or surpass goal
  15. # 3. If we managed to hit goal exactly, we are done. Otherwise, start second process
  16. # 4. In the second process we resort data in ascending order and try until we reach or surpass goal
  17. #
  18. # This should theoretically result in using the lower yield people the least, as well as getting as close as possible
  19. # to the goal without going over.
  20. import argparse
  21. import sys
  22. import locale
  23. # Setup command line arguments
  24. # I did goal and days partly just because I wanted to play with the values
  25. parser = argparse.ArgumentParser(description='Determine panel distribution')
  26. parser.add_argument('file_name', metavar='<File Name>', type=str, help='file containing panel data')
  27. parser.add_argument('-g', '--goal', metavar='<Goal>', type=int, help='Goal we are trying to reach (default 250000)', default=250000)
  28. parser.add_argument('-d', '--days', metavar='<Days>', type=int, help='Number of days to reach goal (default 7)', default=7)
  29. # A list of dictionaries containing the necessary data on each person
  30. # Also stores the set of panels to be assigned to each person
  31. # This is pulled from the problem description, of course
  32. people = [
  33. {'name': 'M', 'yield': 1, 'pan_a_day': 1, 'panels': [] },
  34. {'name': 'GM', 'yield': .95, 'pan_a_day': 2, 'panels': [] },
  35. {'name': '?', 'yield': .85, 'pan_a_day': 3, 'panels': [] },
  36. {'name': 'GB', 'yield': .6, 'pan_a_day': 4, 'panels': [] },
  37. ]
  38. # Simple function, simply loads data from file_name and converts it to int, puts in list data, and returns data
  39. # The data list contains tuples of (index, value) to preserve original index later when sorting
  40. # If it gets something that isn't a number it'll tell you about it, make that entry 0, then continue like nothing happened
  41. def get_data(file_name):
  42. data = []
  43. with open(file_name, 'r') as _file:
  44. for line_num, line in enumerate(_file, 1):
  45. try:
  46. line = int(line)
  47. except ValueError:
  48. sys.stderr.write('Skipping invalid data at line: ' + str(line_num) + '\n')
  49. # This is so that we don't miss a panel index
  50. data.append(0)
  51. else:
  52. data.append((line_num - 1, int(line)))
  53. return data
  54. # Grab the data and arguments
  55. args = parser.parse_args()
  56. data = get_data(args.file_name)
  57. days = args.days
  58. goal = args.goal
  59. # Grab replacement cost of panels
  60. replace_cost = data.pop(0)[1]
  61. # Sort by the 'value' column, descending, to get list ready for processing
  62. data.sort(key=lambda datem: datem[1], reverse=True)
  63. current_money = 0
  64. panel = 0
  65. # This loop goes through each person, people is already setup to be descending by yield
  66. for person in people:
  67. for x in range(0, person['pan_a_day'] * days):
  68. # This is how much the current panel is worth, taking into account yield and
  69. # replacement cost
  70. additional_amt = data[panel][1] * person['yield'] - replace_cost
  71. # If the next panel in list does not meet or go past the goal, add to person's panel set
  72. # and increment current_money by additional_amt
  73. if current_money + additional_amt <= goal:
  74. current_money += additional_amt
  75. person['panels'].append((data[panel][0], data[panel][1]))
  76. panel += 1
  77. # Otherwise, we need to switch gears and look for the smallest possible panel to finish
  78. else:
  79. data.sort(key=lambda datem: datem[1])
  80. # Have to have this up here in case there was a perfect match
  81. if current_money >= goal:
  82. break;
  83. for y in range(0, len(data) - panel):
  84. additional_amt = data[y][1] * person['yield'] - replace_cost
  85. if current_money + additional_amt >= goal:
  86. current_money += additional_amt
  87. person['panels'].append((data[y][0], data[y][1]))
  88. break;
  89. if current_money >= goal:
  90. break;
  91. # Print the output, all pretty like
  92. for person in people:
  93. print ' '.join([person['name'], '=', repr(person['panels'])])
  94. # Add up how much money is left
  95. money_left = 0
  96. for x in range(panel, len(data)):
  97. money_left += data[x][1]
  98. # Print out how much money is left
  99. locale.setlocale(locale.LC_ALL, '')
  100. print 'Total cash left in bannana stand: $' + format(money_left, "n")