I am building a shopping list feature as part of a cookery school application with C#.
The shopper needs to know how much of a given ingredient to buy to cover the class needs. For practicality, quantities need to be rounded up to purchase units.
For example.
A class requires 40cm of foil per person. There are 15 persons so we need 600cm of foil for the class. There are 34 classes running so over all we need 600 * 34 = 20400cm of foil.
Foil is bought in rolls of 2000cm. We know that we will have to give each class one roll to cover their needs. We know this because we know each class needs less than a whole roll.
The problem is that I want to be able to mathematically calculate the number of units required reliably from the total of 20400. If I divide the total by the unit:
20400 / 2000 = 10.2 (or rounded up to eleven rolls).
But this is wrong because there are 34 classes and I need to give each class a whole roll. So the correct purchase amount is 34 rolls.
Does anyone know of a way to achieve this from the total require using math? Or to work out how many rolls for each class based on the class requirement?
So
600cm requires 1 roll 2100cm requires 2 rolls 3100 requires 2 rolls 4100 requires 3 rolls
Perhaps a loop that checks the quantity against multiples of the unit quantity? Can anyone suggest a method?
Update: What I really needed was just this from below:
int rollCount = (int)Math.Ceiling(8060f / 2000f);
CodePudding user response:
Since the requirement is that each class receives an integer number of foil rolls, then the rounding must happen at the class level, and not at the overall school level.
const float foilRollLength = 2000;
public int OrderFoilRolls(int numClasses, int numPersonsPerClass, float minRollPerPerson)
{
float minRollPerClass = numPersonsPerClass * minRollPerPerson;
int rollCountPerClass = (int)Math.Ceiling(minRollPerClass/foilRollLength);
return numClasses * rollCountPerClass;
}
Let's look at your example
public int OrderFoilRolls(34, 15, 40f)
{
600f = 15 * 40f;
1 = (int)Math.Ceiling( 600f / 2000f );
return 34 * 1;
}
Here are some examples of accounting that I did for testing
Classroom #Students Foil [ft] #Rolls
Art 1 23 920 1
Art 2 30 1200 1
Art 3 21 840 1
Art 4 15 600 1
Art 5 7 280 1
Art 6 29 1160 1
Art 7 38 1520 1
Art 8 65 2600 2
Art 9 25 1000 1
Art 10 55 2200 2
Art 11 36 1440 1
Art 12 56 2240 2
Art 13 63 2520 2
Art 14 31 1240 1
Art 15 59 2360 2
Art 16 37 1480 1
Art 17 54 2160 2
Art 18 60 2400 2
Art 19 18 720 1
Art 20 50 2000 1
Art 21 22 880 1
Art 22 10 400 1
Art 23 31 1240 1
Art 24 41 1640 1
Art 25 10 400 1
Art 26 29 1160 1
Art 27 17 680 1
Art 28 29 1160 1
Art 29 42 1680 1
Art 30 64 2560 2
Art 31 53 2120 2
Art 32 36 1440 1
Art 33 10 400 1
Art 34 47 1880 1
In total school needs 43 rolls of foil.
Since this is C# you might as well start using class structures for organizing this information.
My proposal is to have a school class containing the classes, and each classroom is linked with requirements depending on what kind of class it is. Now each class can generate a readonly structure of class supplies, and they can be aggregated together, to sum up all the supplies needed for the school.
This class hierarchy is flexible enough to accommodate multiple supplies, each with its own requirement (per student) and limitation (order minimums). So each classroom may have different requirements and different numbers of students.
Here is the code I used for the example above:
namespace SO.Q72559914
{
class Program
{
static readonly Random rng = new Random();
static void Main(string[] args)
{
School school = new School();
ClassRequirements artRequirements = new ClassRequirements()
{
FoilPerStudent = 40f,
};
// Fill school with classes
school.AddClass("Art", artRequirements, 34);
// Fill classes with students
for (int i = 0; i < school.Classes.Count; i )
{
// pick a random number of students
school.Classes[i].StudentCount = rng.Next(5, 66);
}
Console.WriteLine($"{"Classroom",-12} {"#Students",-12} {"Foil Req'd",-12} {"#Rolls",-6}");
foreach (var room in school.Classes)
{
ClassSupplies classSupplies = room.OrderSupplies();
Console.WriteLine($"{room.Name,-12} {room.StudentCount,-12} {room.StudentCount * room.Requirements.FoilPerStudent,-12} {classSupplies.FoilRolls,-6}");
}
Console.WriteLine();
ClassSupplies totalSupplies = school.OrderSupplies();
Console.WriteLine($"In total school needs {totalSupplies.FoilRolls} rolls of foil.");
}
}
public static class SupplyLimits
{
public const float FoilLength = 2000f;
}
public class ClassRequirements
{
public float FoilPerStudent { get; set; }
}
public struct ClassSupplies
{
public ClassSupplies(int foilRools) : this()
{
FoilRolls = foilRools;
}
public int FoilRolls { get; }
public static ClassSupplies operator (ClassSupplies a, ClassSupplies b)
=> new ClassSupplies(a.FoilRolls b.FoilRolls);
}
public class Classroom
{
public ClassRequirements Requirements { get; set; }
public int StudentCount { get; set; }
public string Name { get; set; } = string.Empty;
public ClassSupplies OrderSupplies()
{
float foilRequired = StudentCount * Requirements.FoilPerStudent;
int foilRolls = (int)Math.Ceiling(foilRequired / SupplyLimits.FoilLength);
return new ClassSupplies(foilRolls);
}
}
public class School
{
public List<Classroom> Classes { get; } = new List<Classroom>();
public void AddClass(string name, ClassRequirements requirements, int count = 1)
{
for (int i = 0; i < count; i )
{
Classes.Add(new Classroom() { Name = $"{name} {i 1}", Requirements = requirements });
}
}
public ClassSupplies OrderSupplies()
{
return Classes.Select((room) => room.OrderSupplies()).Aggregate((sum, item) => sum item);
}
}
}
CodePudding user response:
This is not so much a C# / programming question, but an algorithm question.
You assume that
- A class requires 40cm of foil per person.
- There are 15 persons so we need 600cm of foil for the class.
- There are 34 classes running so over all we need 600 * 34 = 20400cm of foil.
and that you can then calculate the number of rolls to be purchased from the 20,400 cm. Instead, you first need to calculate the purchase size per class:
- A class requires 40cm of foil per person.
- There are 15 persons so we need 600cm of foil for the class.
- So for each class you need 600 / 2000 = 0.3 rolls for the class. Round up to one roll per class.
- There are 34 classes running so over all we need 34 * 1 = 34 rolls.
CodePudding user response:
Well this seems to work but it's not elegant:
decimal amnt = 4010;
decimal packSize = 2000;
int i=0;
bool y=true;
while(y){
if( amnt <= packSize){
i ;
break;
}
else if(amnt > packSize)
{
packSize = packSize;
}
i ;
}
Console.WriteLine("Units: " i);
This returns 3. Which is correct. Because we need three rolls for the class when 4010cm are required.