I am stuck with this for quite a while. What I want my program to do :
I will have two lists. One of quantity and one of price. I want to multiply two according to their serial(example : quantity[i] * price[i]) and add the multiplication result together and get a specific number lets say I add them and I get 100 but I want 101.123 and the way I want to achieve is adding 0.001 to the first price number (I cant touch the quantity number) and check if it matches the answer I wanted. I cant add more than 5 so if it fails to get the number from the first number I want to move to the second one and leave the first one as it was before. Any one? Here's where i have gotten.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ultimateproject_beginner_ {
class Program {
static List<decimal> QuantityList() {
Console.WriteLine("Quantity");
Console.WriteLine();
List<decimal> quantityList = new List<decimal>();
for (;;) {
string stringQuantityNumber = Console.ReadLine();
decimal quantityNumber = 0M;
if (stringQuantityNumber == "done") {
break;
} else {
if (decimal.TryParse(stringQuantityNumber, out quantityNumber)) {
quantityList.Add(quantityNumber);
}
}
}//end of for loop
return quantityList;
}
static List<decimal> PriceList() {
Console.WriteLine("Price");
List<decimal> priceList = new List<decimal>();
for (;;) {
string stringPriceNumber = Console.ReadLine();
decimal priceNumber = 0M;
if (stringPriceNumber == "done") {
break;
} else {
if (decimal.TryParse(stringPriceNumber, out priceNumber)) {
priceList.Add(priceNumber);
}
}
}//end of for loop
return priceList;
}
static void Main(string[] args) {
List<decimal> quantityList = QuantityList();
List<decimal> priceList = PriceList();
decimal destination = 101.123M;
decimal sum = 0M;
for (int i = 0; i < quantityList.Count; i++) {
decimal product = priceList[i] * quantityList[i];
sum = sum + product;
}
Console.ReadKey(true);
}
}
}
I have tried to make it work with some nested for loops but I get stuck where I have to multiply the new value with all other ones.
What I get: 100, What I want : 101.123 How: by adding 0.001 to priceList and check if the sum is 101.123
One approach to dealing with this is to compute the total on first path, then figure out how many additions you would need, and then perform the adjustments. Note that it is possible that you wouldn't be able to reach the desired target, because the max value that you can add is limited by $0.05 times the total quantity of all items ordered. If the sum is $100, you need $101.23, but the order has only ten items in all, the highest you can get with $0.04 per item is $100.50.
You can compute the total using LINQ:
var total = quantityList.Zip(priceList, (q, p) => q*p).Sum();
Compute the value remaining to be assigned, and go through the individual rows, and do the adjustment until remaining drops to zero:
var remaining = destination - total;
for (int i = 0; remaining > 0 && i < quantityList.Count; i++) {
var quantity = quantityList[i];
// Avoid crashes on zero quantity
if (quantity == 0) {
continue;
}
// We cannot assign more than quantity * 0.05
var toAssign = Math.Min(remaining, quantity * 0.05);
remaining -= toAssign;
// Split the amount being assigned among the items
priceList[i] += toAssign / quantity;
}
if (remaining > 0) {
Console.WriteLine("Unable to distribute {0:C}", remaining);
}
Note: Ideally, you should consider creating a class representing quantity/price pairs, rather than using parallel lists.
After sum is calculated, compare it to destination. If sum < destination, then calculate number of 0.001 increments needed as count = (destination - sum) / 0.001. If this is less than 5, then add this many to the first price, otherwise add five of them (0.005), and then subtract 5 from count. If count > 0 then repeat the process for the second price, etc. If count is greater than pricelist.Count * 5, you can't reach the destination price.
Related
I need to generate all possible values to a scheduler who works like this:
Some hours of the week can be already chosen.
The week of work is defined by the following pattern "???????" question marks can be replaced.
Given a maximum of hours, I need to replace the question marks with digits so that the sum of the scheduled hours match the hours need to work in a week returning a string array with all possible schedules, ordered lexicographically.
Example:
pattern = "08??840",
required_week_hours= 24
In this example, there are only 4 hours left to work.
calling this:
function List<String> GenerateScheduler(int workHours, int dayHours, string pattern){}
public static void Main(){
GenerateScheduler(24, 4, "08??840");
}
This would return the following list of strings:
0804840
0813840
.......
.......
0840840
I'm not very familiar with algorithms, which one I could use to solve this problem?
This sounds like a problem where you have to generate all permutations of a list of a certain amount of numbers that sum up to a certain number. First, you need to sum up the hours you already know. Then you need to count up the number of ? aka the number of shifts/days you do not know about. Using these parameters, this is what the solution will look like,
public List<string> GenerateScheduler(int workHours, int dayHours, string pattern){
int remainingSum = workHours;
int unknownCount = 0;
// first iterate through the pattern to know how many ? characters there are
// as well as the number of hours remaining
for (int i = 0; i < pattern.Length; i++) {
if (pattern[i] == '?') {
unknownCount++;
}
else {
remainingSum -= pattern[i] - '0';
}
}
List<List<int>> permutations = new List<List<int>>();
// get all the lists of work shifts that sum to the remaining number of hours
// the number of work shifts in each list is the number of ? characters in pattern
GeneratePermutations(permutations, workHours, unknownCount);
// after getting all the permutations, we need to iterate through the pattern
// for each permutation to construct a list of schedules to return
List<string> schedules = new List<string>();
foreach (List<int> permutation in permutation) {
StringBuilder newSchedule = new StringBuilder();
int permCount = 0;
for (int i = 0; i < pattern.Length(); i++) {
if (pattern[i] == '?') {
newSchedule.Append(permutation[permCount]);
permCount++;
}
else {
newSchedule.Append(pattern[i]);
}
}
schedules.Add(newSchedule.ToString());
}
return schedules;
}
public void GeneratePermutations(List<List<int>> permutations, int workHours, int unknownCount) {
for (int i = 0; i <= workHours; i++) {
List<int> permutation = new List<int>();
permutation.Add(i);
GeneratePermuationsHelper(permutations, permutation, workHours - i, unknownCount - 1);
}
}
public void GeneratePermutationsHelper(List<List<int>> permutations, List<int> permutation, int remainingHours, int remainingShifts){
if (remainingShifts == 0 && remainingHours == 0) {
permutations.Add(permutation);
return;
}
if (remainingHours <= 0 || remainingShifts <= 0) {
return;
}
for (int i = 0; i <= remainingHours; i++) {
List<int> newPermutation = new List<int>(permutation);
newPermutation.Add(i);
GeneratePermutationsHelper(permutations, newPermutation, remainingHours - i, remainingShifts - 1);
}
}
This can be a lot to digest so I will briefly go over how the permutation recursive helper function works. The parameters go as follows:
a list containing all the permutations
the current permutation being examined
the remaining number of hours needed to reach the total work hour count
the number of remaining shifts (basically number of '?' - permutation.Count)
First, we check to see if the current permutation meets the criteria that the total of its work hours equals the amount of hours remaining needed to complete the pattern and the number of shifts in the permutation equals the number of question marks in the pattern. If it does, then we add this permutation to the list of permutations. If it doesn't, we check to see if the total amount of work hours surpasses the amount of hours remaining or if the number of shifts has reached the number of question marks in the pattern. If so, then the permutation is not added. However, if we can still add more shifts, we will run a loop from i = 0 to remainingHours and make a copy of the permutation while adding i to this copied list in each iteration of the loop. Then, we will adjust the remaining hours and remaining shifts accordingly before calling the helper function recursively with the copied permutation.
Lastly, we can use these permutations to create a list of new schedules, replacing the ? characters in the pattern with the numbers from each permutation.
As per OP, you already know the remaining hours, which I assume is given by the parameter dayHours. So, if you were to break down the problem further, you would need to replace '?' characters with numbers so that, sum of new character(number) is equal to remaining hours(dayHours).
You can do the following.
public IEnumerable<string> GenerateScheduler(int totalHours,int remainingHours,string replacementString)
{
var numberOfPlaces = replacementString.Count(x => x == '?');
var minValue = remainingHours;
var maxValue = remainingHours * Math.Pow(10,numberOfPlaces-1);
var combinations = Enumerable.Range(remainingHours,(int)maxValue)
.Where(x=> SumOfDigit(x) == remainingHours).Select(x=>x.ToString().PadLeft(numberOfPlaces,'0').ToCharArray());
foreach(var item in combinations)
{
var i = 0;
yield return Regex.Replace(replacementString, "[?]", (m) => {return item[i++].ToString(); });
}
}
double SumOfDigit(int value)
{
int sum = 0;
while (value != 0)
{
int remainder;
value = Math.DivRem(value, 10, out remainder);
sum += remainder;
}
return sum;
}
I've been stuck on this problem for a week, I searched and the results I found don't seem to fit with what I want to do.
Problem:
A person will purchase something and the cashier will give back the change based on the person's dollar bills.
What I've done: I'm detecting how much money the buyer has in total and the amount of each dollar bill, comparing if the buyer has the required amount or not.
But now I need to get the amount of required bills the buyer has to subtract from the purchase price and remove them to complete the payment. A greedy algorithm is OK for me here, I can start from highest bill and go down from there until the sum of his bills are less or equal than the purchase total. Then the cashier just give the remain
I've the code to give the change, which is a simple greedy algorithm by dividing and getting the remainder of division. I believe to solve my problem, I could do something similar to what I done for the money change.
The bills are: 1, 5, 10, 20, 50, 100.
Code example:
int Value = 150 //value that needs to be paid
int q100 = 1; //dollar bills amount that needs to subtract from Value
int q50 = 0;
int q20 = 0;
int q10 = 5; //this example I've one $50 dollar bill and five $10, how can I subtract from here no matter how many bills I've
int q5 = 0;
int q1 = 0;
int q05 = 0;
decimal Total = 0;
int Total = (n100 * 100) + (n50 * 50) + (n20 * 20) + (n10 * 10) + (n5 * 5) + (n1 * 1);
if(Value > Total)
{
//Doesn't have enough money
return;
}
//stuck here
Can anyone give me a lead to go on? I might be searching in the wrong place.
EDITED: I came with the solution, following Jason Lang answer partially.
for (int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
// basically keep paying with e.g. hundreds as long as the amount
// left is 100+, etc, then go on to 50's etc
while (amountLeftToPay > 0 && myBills[i] > 0)
{
amountLeftToPay -= billValues[i];
myBills[i]--;
paidBills[i]++;
}
}
What happened: myBills are setting the values before anything, this for/while iterates until AmountLeftToPay is 0 or less than 0 while saving the bills that the customer paid. (The bills are later removed in other function, it doesn't work with basic C#, it is based off from a framework from a game.)
Then I made the negative value become positive multiplying by -1. That value is handed to the function to be converted as change.
Here is the code for a little test I did on a console application for debugging: http://pastebin.com/GekLLjB3
At the end myBills values are the customers leftover bills before receiving any change, paidBills is the removed bills.
First up, any time you're making a big number of variables like that with numbers on them, convert that to a single array instead. Much neater, and it's almost always better.
int[] billValues = {1, 5, 10, 20, 50, 100};
Then you can have arrays for your starting bills, what was paid and what change you got, without having an explosion of variable names:
int[] myBills = new int[6]; // which bills I have
int[] paidBills = new int[6]; // what bills I paid
int[] changeBills = new int[6]; // what bills I got as change
These match the "slots" in the billValue array, so you don't actually need to make all those separate variables.
Have the pay amount separate:
int amountToPay = 150;
Then, you can run some while loops to deduct bills from the correct arrays and add them to other arrays. The first thing you want to do is loop through your bills and deduct the largest bills that are equal or less than the amountToPay. You need to keep track of the amount left to pay, as each bill is handed over.
int amountLeftToPay = amountToPay;
Then, deduct the biggest bill that fits
for(int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
// basically keep paying with e.g. hundreds as long as the amount
// left is 100+, etc, then go on to 50's etc
while (billValues[i] <= amountLeftToPay && myBills[i] > 0)
{
amountLeftToPay -= billValues[i];
myBills[i] --;
paidBills[i] ++;
}
}
At this point, all bills that you have that fit inside the amount to pay have been paid. There could be a situation now however where the amount left to pay is greater than zero, but it's less than any particular bill that you have. To sort that out, you need to find out what is the smallest bill that's greater than the amount left to pay. So you need to loop up, this time:
int billToUse = -1; // -1 will mean not found
for(int i = 0; i < billValues.Length; i++) // smallest first
{
if(amountLeftToPay <= billValues[i] && myBills[i] > 0)
{
billToUse = i;
break;
}
}
Here we want to record how much change is owed, if any
int amountOwedAsChange = 0;
if(billToUse >= 0) // i.e. one was found
{
amountOwedAsChange = billValues[billToUse] - amountLeftToPay;
amountLeftToPay = 0;
}
Righto, this is the home stretch. Working out what bills are owed as change is basically the same as what we did when we worked out what bills to pay with, except we can assume that the cash register has unlimited bills. But you could actually convert the original "paying bills" code into a function, and model what's in the cash register so that they only pay with what they have. Once you break things into functions that becomes much, much easier. You just model the cash register as another "person" who themselves have a myBills array. But for now, we hard-code the simpler version where cash registers always have bills they need:
for(int i = billValues.Length - 1; i >= 0; i--) // biggest FIRST
{
while (billValues[i] <= amountOwedAsChange)
{
amountOwedAsChange -= billValues[i];
changeBills [i] ++;
}
}
So at this point, amountLeftToPay and amountOwedAsChange are both zero, and the information has been packed into myBills, and changeBills, and you can cycle through those and print out text describing what was paid and what change you got.
For added points, you can expand this to cover coins very easily. You just code everything in cents, and multiply all dollar values by 100, expanding out the billValues table (and increasing the size of the other arrays to match) as needed.
Here's a way you can breakdown the amount into the required notes:
var bills = new [] { 1, 5, 10, 20, 50, 100, };
var value = 150;
var breakdown =
bills
.OrderByDescending(x => x)
.Aggregate(new { value, bills = new List<int>() },
(a, b) =>
{
var v = a.value;
while (v >= b)
{
a.bills.Add(b);
v -= b;
}
return new { value = v, a.bills };
})
.bills
.GroupBy(x => x)
.Select(x => new { Bill = x.Key, Count = x.Count() });
That gives me:
You can easily extend this to account for coins too.
var bills = new double[] { 0.01, 0.02, 0.05, 0.1, 0.2, 0.5, 1, 5, 10, 20, 50, 100, };
var value = 213.47;
var breakdown =
bills
.OrderByDescending(x => x)
.Aggregate(new { value, bills = new List<double>() },
(a, b) =>
{
var v = a.value;
while (v >= b)
{
a.bills.Add(b);
v -= b;
}
return new { value = v, a.bills };
})
.bills
.GroupBy(x => x)
.Select(x => new { Bill = x.Key, Count = x.Count() });
That gives:
Hi there I'm trying to write a method that reads every number in a list and detects where it spikes and drops. This is what I have so far:
I basically figure if I loop through the list, loop through it again to get the next number in the list, then detecting if it's more or less. If it's more it'll save to one list, vice versa.
What I want this method to do is determine where there's a spike of 100 or more, save the point that it does this (which is 'counter') and also save the points where the numbers drop.
This so far notices only a drop and it will save every number in the list until it spikes again and once it has spiked it shows no numbers, until it drops again and so on.
I've put 'check' and 'check2' to try and counteract it saving every number after it notices a drop and only save it once but no luck.
Any ideas?
public void intervalDetection()
{
//Counter is the point in the list
int counter = 0;
int spike = 0;
int drop = 0;
//Loop through power list
for (int i = 0; i < powerList.Count(); i++)
{
counter++;
int firstNumber = powerList[i];
//Loop again to get the number after??
for (int j = 1; j < 2; j++)
{
//Detect Spike
spike = firstNumber + 100;
drop = firstNumber - 100;
if (powerList[j] > spike)
{
if (check2 == false)
{
intervalStartList.Add(counter);
check2 = true;
check = false;
}
}
//Detect Drop
else if (powerList[j] < drop)
{
if (check == false)
{
intervalEndList.Add(counter);
check = true;
check2 = false;
}
}
}
Create integer "average"
Loop through List/Array and add each value to average
Divide average by the count of the List/Array
Loop through List/Array and check deviation to the average integer
derp
Code example:
public class DSDetector {
public static List<int>[] getDropsnSpikes(List<int> values, int deviation) {
List<int> drops = new List<int>();
List<int> spikes = new List<int>();
int average = 0;
foreach (int val in values) {
average += val;
}
average = average/values.Count;
foreach (int val in values) {
if (val < average - deviation) {
drops.add(val);
}
if (val > average + deviation) {
spikes.add(val);
}
}
//derp.
return new List<int>{drops, spikes};
}
}
not tested but I think it works. Just try it.
What exactly do you mean saying "peaks" and "drops"?
Let's say you have following list of integers
112, 111, 113, 250, 112, 111, 1, 113
In this case value 250 is peak and 1 drop relative to average value and you can get it using Kai_Jan_57 answer.
But also 250 is peak to previous value 113 and 112 is drop for 250.
If you want to find local peaks and drops you can check each value relative to previous and next: find average as avg=(val[i-1]+val[i+1])/2 and check if val[i]>avg + 100 (peak) or val[i]
I was able to write this tiny segment of this program to display the numbers in Ascending order but i still cant get it to display it in Descending order.
Basics of what this program should do is takes in two number values from the user in the form of "From" and "To" and displays it as a list in the listbox. The users choice of either ascending or descending order depends on which of the two Radio buttons he has selected.
private void btnCalc_Click(object sender, EventArgs e)
{
double fromNum, toNum, total = 0;
fromNum = double.Parse(txtFrom.Text);
toNum = double.Parse(txtTo.Text);
lstResult.Items.Clear();
lblResult.Text = "";
if (radAsc.Checked)
{
while (fromNum <= toNum)
{
lstResult.Items.Add(fromNum);
total = total + fromNum;
fromNum++;
}
}
else
{
while (fromNum >= toNum)
{
lstResult.Items.Add(fromNum);
total = total + toNum;
toNum--;
}
}
lblResult.Text = total.ToString();
}
Here's an image to what the program looks like.
http://imgur.com/SVwN3Tx
Note:- I am completely new to C# and I've just started taking it in College.
I suggest using for loop instead of while which makes the code easy to implement:
if (radAsc.Checked)
{
// num += 1: - I've seen odds/even switch on the screenshot
// so you may want to change/add num += 1 into num += 2
for (double num = fromNum; num <= toNum; num += 1) {
lstResult.Items.Add(num);
total = total + num;
}
}
else
{
// Descending order:
// - start from the bottom (toNum)
// - loop until the top (fromNum)
// - descend by 1 (num -= 1)
for (double num = toNum; num >= fromNum; num -= 1) {
lstResult.Items.Add(num);
total = total + num;
}
}
You're decrementing the wrong value
while (fromNum >= toNum)
{
lstResult.Items.Add(fromNum);
total = total + toNum;
toNum--;
}
So, here's what you're doing:
Say fromNum is 10, and toNum is 1.
After your first iteration, fromNum is still 10 but toNum is 0. Decrement the fromNum instead of toNum and it should work accordingly.
EDIT
Couple things to take note. If total is collecting the sum of all numbers, a neat way to write:
total = total + value;
is
total += value;.
You should also verify that the numbers will actually work before going into your logic. So if the radio button is selected for Ascending order, you want to make sure fromNum is less than toNum, and maybe throw up a message box if they're not:
if(fromNum < toNum)
{ run logic .... }
else
{ alert user ... }
I am in the process of developing an application which calculates the shared acquired in a product over a specified time period (Term).
After the calculations have been performed, it is necessary for me to aggregate the data into groups based on a predefined review period (for example if the time required to gain 100% ownership of the product is 25 years, and the review period value is 5 years, I would have 5 sets of data aggregations for the agreement).
I perform the aggregations as shown by looping through my calculation result set:
if (Year% ReviewPeriod == 0)
{
// Perform Aggregations
}
This works fine in most scenarios.
However I do have a number of scenarios where the product reaches 100% ownership before the end of term.
What I need to be able to do is aggregate the calculations performed based on the ReviewPeriod variable, but if the final number of values in the calculations is not equal to the review period, aggregate the items based on the number of items remaining.
For example, given a 22 year term, data would be aggregated based on the Review Period variable, however if there is a remainder, then the remainder should be aggregated based on the value of the remainder.
Worked Example
Year 0 - 5 = 5 Aggregations
Year 6 - 10 = 5 Aggregations
Year 11 - 15 = 5 Aggregations
Year 16 - 20 = 5 Aggregations
Year 21 - 22 = 2 Aggregations
Could anyone help me with the logic to aggregate the data as I have described.
Probably the simplest way would be something like:
for ( int year = 0; year <= max_year; year++ ) {
if ( year % reviewPeriod == 0 ) {
// start a new aggregation
}
// add year to current aggregation
}
You could keep a list of aggregations and add a new one at the start of each period.
Here is a working example that just groups years in lists:
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
namespace Aggregations
{
class Program
{
static void Main(string[] args)
{
int maxYear = 22;
int period = 5;
int year = 1985;
List<List<int>> aggregations = new List<List<int>>();
int i = -1;
for (int y = 0; y <= maxYear; y++)
{
if (y % period == 0)
{
aggregations.Add(new List<int>());
i++;
}
aggregations.ElementAt(i).Add(year);
year++;
}
foreach ( List<int> l in aggregations )
{
foreach (int yy in l)
{
Console.Write(yy + " ");
}
Console.WriteLine();
}
}
}
}
You've not really given enough of your code to go on. Hopefully you should be able to use this however your loop is currently set up. It "leaks" the mod value to the outside of the loop; after the loop is over, you can check the final mod value to see how many aggregations are left.
int modValue = 0;
for //foreach/while/... - your loop here
{
...
modValue = Year % ReviewPeriod;
if (modValue == 0)
{
// Perform Aggregations
}
...
} // end of your loop
if (modValue != 0)
{
// Perform final aggregation. There are modValue items to aggregate.
}
I think my suggestion is not worth 300rep bounty, and either I misunderstood your problem, or you've overshot the bounty..
Do your existing code that calculates the final aggregations works well? If so, then to determine the ranges yo umay just use modulo (%) and simple math:
int minYear = ...the first year // inclusive, i.e. 1970
int maxYear = ...the last year // inclusive, i.e. 2012
int span = maxYear - minYear + 1; // 1970..2012->43, 2001..2006->6
int fullFives = span / 5; // 1970..2012->8, 2001..2006->1
int remainder = span % 5; // 2001..2006->3, 2001..2006->1
for(int i=0; i<fullFives; ++i)
{
int yearFrom = minYear + 5*i
int yearTo = minYear + 5*(i+1) - 1
// 1970..2012 -> 1970-1974, 1975-1979,1980-1984,1985-1989,1990-1994,1995-1999,2000-2004,2005-2009
// 2001..2006 -> 2001-2005
aggregate(yearFrom, yearTo);
}
if(remainder > 0)
{
int yearFrom = minYear + 5*fullFives
int yearTo = minYear + maxYear
// 1970..2012 -> 2010-2012
// 2001..2006 -> 2006-2006
aggregate(yearFrom, yearTo);
}
This is written "out of thin air", I've not checked/compiled it - it is just to sketch the idea.
Note: you've said that everything works but sometimes "a number of scenarios where the product reaches 100% ownership before the end of term." - that would suggest that you rather have an error in the calculations, not in the looping. If the error were in the loop or year boundary detection, then probably almost all would be off. It's hard to say without more of the calculating code is revealed.
The code sample will fire on years 0, 5, 10 etc rather than for every year.
If you just need the number of years to aggregate when that code fires, and the term can be set in advance when a product reaches 100% ownership early, I think this would work:
int term = 22;
int reviewperiod = 5;
for (int year = 0; year < term; year++)
{
if (year % reviewperiod == 0)
{
var endyear = Math.Min(year + reviewperiod, term);
Console.WriteLine("Aggregate years {0} to {1}, {2} Aggregations ", year, endyear, endyear - year);
}
}
Do you think of something like
private int reviewPeriod = 5;
public void Aggregate(int term)
{
Enumerable.Range(0, term)
.ToList()
.Foreach(this.AggregateYear);
}
when this.AggregateYear is defined as follows
public void AggregateYear(int year)
{
var currentRemainder = year % this.reviewPeriod;
var aggregatePeriod = (currentRemainder == 0)
? this.reviewPeriod
: currentRemainder;
this.PerformAggregation(aggregatePeriod);
}
and this.PerformAggregation is defined as follows
private void PerformAggregation(int aggregatePeriod)
{
//...
}
Assuming this data is in memory (since you have not specified otherwise), then you can just use the GroupBy function from Linq:
struct YearValue
{
public int Year, Value;
}
static void Main()
{
// Create some data, hopefully representative of what you are dealing with...
Random r = new Random();
YearValue[] dataValues = new YearValue[22];
for (int i = 0; i < dataValues.Length; i++)
dataValues[i] = new YearValue {Year = i, Value = r.Next(200)};
// Average of values across 'ReviewPeriod' of five:
foreach (var item in dataValues.AsEnumerable().GroupBy(i => i.Year / 5))
{
YearValue[] items = item.ToArray();
Console.WriteLine("Group {0} had {1} item(s) averaging {2}",
item.Key,
items.Length,
items.Average(i => i.Value)
);
}
}
This program then outputs the following text:
Group 0 had 5 item(s) averaging 143.6
Group 1 had 5 item(s) averaging 120.4
Group 2 had 5 item(s) averaging 83
Group 3 had 5 item(s) averaging 145.2
Group 4 had 2 item(s) averaging 98.5