Get last 'N' quarters in C# - c#

Suppose the current quater is 3 and the year is 2011. How can I get the last 5 quarters
Desired output:
Q3-2011
Q2-2011
Q1-2011
Q4-2010
Q3-2010
The Q and '-' is appended.
I am trying as under
int generateQuater = 5;
int currentQuater = 3;//GetQuarter(DateTime.Now.Month);
int currentYear = DateTime.Now.Year;
List<string> lstQuaterYear = new List<string>();
lstQuaterYear.Add(string.Concat('Q',currentQuater, '-', currentYear));
for (int i = generateQuater; i > 0; i++)
{
//code to be placed
}
Thanks

You have to decrease your loop variable. The rest is not too difficult math.
Its also not necessary to handle the first iteration in any special way:
for (int i = generateQuater; i > 0; i--)
{
lstQuaterYear.Add(string.Format("Q{0}-{1}", currentQuater, currentYear));
if (--currentQuater == 0)
{
currentQuater = 4;
currentYear--;
}
}

As a pure LINQ expression:
public IEnumerable<String> GetQuarters(int start, int year, int count)
{
return (from q in Enumerable.Range(0, count)
select String.Format("Q{0}-{1}", (start - q) + (((q + 1) / 4) * 4) , year - ((q + 1) / 4)));
}
The math is somewhat ugly but does work, to use it you can just do:
foreach (String quarter in GetQuarters(3, 2011, 5))
{
Console.WriteLine(quarter);
}

Your for loop should go from 0 to your variable, when you're increasing i.
The inner code could be something like:
currentQuarter--;
if(currentQuarter == 0)
{
currentQuarter = 4;
currentYear--;
}

Don't forget to refactor it :)
int count = 5;
int currentQuarter = GetQuarter(DateTime.Now.Month);
int currentYear = DateTime.Now.Year;
List<string> lstQuaterYear = new List<string>();
for (int i = count; i > 0; i--)
{
lstQuaterYear.Add(string.Concat('Q', currentQuarter, '-', currentYear));
currentQuarter--;
if (currentQuarter == 0)
{
currentQuarter = 4;
currentYear--;
}
}

One way is to check for year roll over and then set the quarter to 4 and decrement the year:
int quarter=3;
int year=2011;
int count=5;
for(int i=0;i<count;i++)
{
lstQuaterYear.Add(string.Format("Q{0} {1}", quarter, year);
quarter--;
if(quarter==0)
{
quarter=4;
year--;
}
}
Alternatively you could calculate a totalQuartal=year+quartal-1. Then decrement it on each step. And finally use year=totalQuartal/4 and quartal=totalQuartal%4+1. But I think the first way is easier to understand.

public static IEnumerable Generate(int number, int currentYear, int currentQuarter)
{
int counter = number;
int quarter = currentQuarter;
int year = currentYear;
while (counter-- > 0)
{
yield return String.Format("Q{0}-{1}", year, quarter);
quarter = quarter>1?quarter-1:4;
year = quarter==4?year-1:year;
}
}

Here is my version (sorry, it is in VB.NET).
The idea is to :
easily find out the quarter based on a date (easy : divide it by 4 ... and add 1 to avoid zeros)
go back in time from the current date, removing 3 month at each time
printout the formatted quarter
the code :
Private Shared Function GetQuarterForDate(ByVal d As DateTime) As Integer
Return (d.Month \ 4) + 1 'integer division
End Function
Private Shared Function GetLastNQuarters(ByVal N As Integer) As IEnumerable(Of String)
Dim myDate = DateTime.Now
Dim res As New List(Of String)()
Do While N > 0
'using yield would be nicer in C# ... does not exist in VB
res.Add(String.Format("Q{0}-{1}", GetQuarterForDate(myDate), myDate.Year))
myDate = myDate.AddMonths(-3)
N = N - 1
Loop
Return res
End Function
<TestMethod()>
Public Sub CanRetrieveQuarter()
Dim quarters = GetLastNQuarters(5)
For Each q In quarters
Console.WriteLine(q)
Next
End Sub
That last "test method" prints out :
Q3-2011
Q2-2011
Q1-2011
Q4-2010
Q3-2010

In case you should do some operations on the quarter period, like check if moment is within a quarter, you can use the Quarter class of the Time Period Library for .NET:
// ----------------------------------------------------------------------
public ITimePeriodCollection GetPastQuarters( int count )
{
TimePeriodCollection quarters = new TimePeriodCollection();
Quarter quarter = new Quarter();
for ( int i = 0; i < count; i++ )
{
quarters.Add( quarter );
quarter = quarter.GetPreviousQuarter();
}
return quarters;
} // GetPastQuarters

Related

Algorithm converting lotto ticket number to integer value and back again

I'm looking for the algorithm to convert a lotto ticket number to an integer value an back again.
Let's say the lotto number can be between 1 and 45 and a tickets contains 6 unique numbers. This means there are a maximum of 8145060 unique lotto tickets.
eg:
01-02-03-04-05-06 = 1
01-02-03-04-05-07 = 2
.
.
.
39-41-42-43-44-45 = 8145059
40-41-42-43-44-45 = 8145060
I'd like to have a function (C# preferable but any language will do) which converts between a lotto ticket and an integer and back again. At the moment I use the quick and dirty method of pre-calculating everything, which needs a lot of memory.
For enumerating integer combinations, you need to use the combinatorial number system. Here's a basic implementation in C#:
using System;
using System.Numerics;
using System.Collections.Generic;
public class CombinatorialNumberSystem
{
// Helper functions for calculating values of (n choose k).
// These are not optimally coded!
// ----------------------------------------------------------------------
protected static BigInteger factorial(int n) {
BigInteger f = 1;
while (n > 1) f *= n--;
return f;
}
protected static int binomial(int n, int k) {
if (k > n) return 0;
return (int)(factorial(n) / (factorial(k) * factorial(n-k)));
}
// In the combinatorial number system, a combination {c_1, c_2, ..., c_k}
// corresponds to the integer value obtained by adding (c_1 choose 1) +
// (c_2 choose 2) + ... + (c_k choose k)
// NOTE: combination values are assumed to start from zero, so
// a combination like {1, 2, 3, 4, 5} will give a non-zero result
// ----------------------------------------------------------------------
public static int combination_2_index(int[] combo) {
int ix = 0, i = 1;
Array.Sort(combo);
foreach (int c in combo) {
if (c > 0) ix += binomial(c, i);
i++;
}
return ix;
}
// The reverse of this process is a bit fiddly. See Wikipedia for an
// explanation: https://en.wikipedia.org/wiki/Combinatorial_number_system
// ----------------------------------------------------------------------
public static int[] index_2_combination(int ix, int k) {
List<int> combo_list = new List<int>();
while (k >= 1) {
int n = k - 1;
if (ix == 0) {
combo_list.Add(n);
k--;
continue;
}
int b = 0;
while (true) {
// (Using a linear search here, but a binary search with
// precomputed binomial values would be faster)
int b0 = b;
b = binomial(n, k);
if (b > ix || ix == 0) {
ix -= b0;
combo_list.Add(n-1);
break;
}
n++;
}
k--;
}
int[] combo = combo_list.ToArray();
Array.Sort(combo);
return combo;
}
}
The calculations are simpler if you work with combinations of integers that start from zero, so for example:
00-01-02-03-04-05 = 0
00-01-02-03-04-06 = 1
.
.
.
38-40-41-42-43-44 = 8145058
39-40-41-42-43-44 = 8145059
You can play around with this code at ideone if you like.
there seem to be actually 45^6 distinct numbers, a simple way is to treat the ticket number as a base-45 number and convert it to base 10:
static ulong toDec(string input){
ulong output = 0;
var lst = input.Split('-').ToList();
for (int ix =0; ix< lst.Count; ix++)
{
output = output + ( (ulong.Parse(lst[ix])-1) *(ulong) Math.Pow(45 , 5-ix));
}
return output;
}
examples:
01-01-01-01-01-01 => 0
01-01-01-01-01-02 => 1
01-01-01-01-02-01 => 45
45-45-45-45-45-45 => 8303765624

How to write out odd numbers in an interval using for function

So my homework is I have to take two numbers from the user then I have to write out the odd numbers in that interval.But the code under doesn't work. It writes out "TrueFalseTrueFalse".
int szam;
int szam2=0;
int szam3=0;
int szam4=0;
Console.Write("Please give a number:");
szam = Convert.ToInt32(Console.ReadLine());
Console.Write("Please give another number:");
szam2 = Convert.ToInt32(Console.ReadLine());
if (szam>szam2)
{
for (szam3=szam, szam4 = szam2; szam4 < szam3; szam4++)
{
Console.Write(szam2 % 2==1);
}
}
else
{
for (szam3 = szam, szam4 = szam2; szam3 < szam4; szam3++)
{
Console.Write(szam3 % 2 ==1);
}
}
So if the two numbers would be 0 and 10, the program has to write out 1, 3, 5, 7, and 9
I would be careful when naming your variables yes its a small piece of code but it gets confusing to people trying to read it.
Based on the requirement, I would guess you want all the odd numbers given a certain range.
const string comma = ",";
static void Main(string[] args)
{
int start = getNumber();
int end = getNumber();
if(start > end)
{
int placeHolder = end;
end = start;
start = placeHolder;
}
string delimiter = string.Empty;
for(int i = start; i < end; i++)
{
if(i % 2 == 1)
{
Console.Write(string.Concat(delimiter,i.ToString()));
delimiter = comma;
}
}
Console.ReadLine();//otherwise you wont see the result
}
static int getNumber()
{
Console.Write("Please enter a number:");
string placeHolder = Console.ReadLine();
int toReturn = -1;
if (int.TryParse(placeHolder, out toReturn))
return toReturn;
return getNumber();
}
as Juharr mentioned in the comments, you need to check the result to print the actual number.
Width Linq you can write:
int szam = 20;
int szam2= 30;
var odds = Enumerable.Range(szam2 > szam ? szam : szam2, Math.Abs(szam-szam2))
.Where(x=>x % 2 != 0);
outputs:
21
23
25
27
29
// so we create a range from low to high (Enumerable.Range(..)
// take only the odd values (x % 2 != 0)
simply wrap it in string.Join to make a single string:
string text = String.Join(",",Enumerable.Range(szam2 > szam ? szam :
szam2,Math.Abs(szam-szam2))
.Where(x=>x % 2 != 0));

Get 1st number between every 10 numbers

I have 120 groups, each group has 10 numbers.
Suppose if 24 is in the loop I want to get in which group it is? Means if 24 is there then I want to get 21 because 24 comes between 21-30.
Give me logic using if or for loop whatever.
Here is my code:
for (int i = 0; i < 120; i++)
{
if (i % 10 == 0)
{
Response.Write(i.ToString());
}
}
Something like that?
static int starter(int n)
{
var x = n % 10;
return n - x + 1;
}
static void Main(string[] args)
{
Console.WriteLine(starter(24));
Console.ReadLine();
}
I do not know how in pack the numbers in groups, so I'm giving you a solution and you have to change it for your own needs.
Suppose the number are packed in an ArrayList and the groups are then packed together in another ArrayList. This way you would have an ArrayList of several ArrayList with number. So my solution would be:
private int FindNumber(int number)
{
int count = 0;
int gindex = -1;
foreach(group g in groups)
{
if(g.contains(number))
gindex = count;
count++;
}
ArrayList aux = groups[gindex];
return aux[0];
}
Edit after reading Jester response. I guess you would like the first number of the 10 groups so
private int FindNumber(int number)
{
int ret
foreach(group g in groups)
{
if(g.contains(number))
{
var x = number % 10;
ret = number - x + 1;
}
}
return ret;
}
Jester response is right in the main idea but that doesn't work if you don't have the number in the group.

c# check if daterange between an interval

I need some clear mind to check if a date range false between another interval. Here is whats happening:
DateTime[] dates = new DateTime[20];
dates[0] = Convert.ToDateTime(initial_date);
for (int i = 1; i <= 19; i++)
{
dates[i] = initial_date.AddYears(i);
}
So i have an array that stores 20 dates. If the initial_date = 1/20/2012 the array goes from dates[0] = 1/20/2012 up to dates[19] = 1/20/2031
and now i want to check if a user selects two dates for example 1/1/2013 and 1/1/2014 the selections falls between the the first element of the array (dates[0]) and the second (dates[1]). so far:
DateTime a1 = Convert.ToDateTime(vtable.Rows[0][0]);
DateTime a2 = Convert.ToDateTime(vtable.Rows[vtable.Rows.Count - 1][0]);
DateTime start = DateTime.MinValue;
DateTime end = DateTime.MaxValue;
for (int i = 0; i < 20; i++)
{
if (a1.CompareTo(dates[i]) >= 0)
{
start = dates[i];
for (int j = 19; j > 0 ; j--)
{
if (a2.CompareTo(dates[j]) >= 0)
{
end = dates[j];
break;
}
}
break;
}
}
this is working up to the point when a user selects a daterange that falls only between one element of the array. Like for example if the selection is 1/30/2012 - 5/30/2012 then start = date[0] and end = date[0]
I know i can simply state at the end if end == unassigned then end = start but i am thinking is better to correct the algorithm than applying a patch at the end
Thank you very much
Store your date ranges as pairs as in start to end, where end would next start - 1 day.
Makes things much clearer in the code.
var rangeMax = dates.Max();
var rangeMin = dates.Min();
DateTime a1 = Convert.ToDateTime(vtable.Rows[0][0]);
DateTime a2 = Convert.ToDateTime(vtable.Rows[vtable.Rows.Count - 1][0]);
if ((a1 > rangeMin) && (a1 < rangeMax) && (a2 > rangeMin) && (a2 < rangeMax))
{
//dates are in given range
}

I need to add ranges and if a range is missed while adding i should display a message

EXAMPLE :if i add a range {1,10}
and another range{15,20}
i should get a message saying the ranges from 11 to 14 are missing.
How are you adding the ranges?
If the ranges are added in order, you can just keep the end of the last range and compare to the start of the range that you add.
If you can add the ranges in any order, you have to do the check when all ranges are added. Sort the ranges on the range start, then loop through the ranges and compare the end of a range with the start of the next range.
update
Example of the second case. First a class to hold ranges:
public class Range {
public int From { get; private set; }
public int To { get; private set; }
public Range(int from, int to) {
From = from;
To = to;
}
}
Create a list of ranges:
List<Range> ranges = new List<Range>();
ranges.Add(new Range(15, 20));
ranges.Add(new Range(1, 10));
Test the ranges:
ranges = ranges.OrderBy(r => r.From).ToList();
for (int i = 1; i < ranges.Count; i++) {
int to = ranges[i - 1].To;
int from = ranges[i].From;
int diff = to.CompareTo(from - 1);
if (diff < 0) {
Response.Write("Range from " + (to + 1).ToString() + " to " + (from - 1).ToString() + " is missing<br/>");
} else if (diff > 0) {
Response.Write("Range ending at " + to.ToString() + " overlaps range starting at " + from.ToString() + "<br/>");
}
}
Note: The code checks for both gaps in the ranges and overlapping ranges. If overlapping ranges is not a problem, just remove the part that checks for diff > 0.
It isn't clear what your code is trying to do, but here's the basic approach you should probably take:
Create a Range type that has a Start and End
Order the collection by the Start property (possibly using Enumerable.OrderBy).
Traverse the pairs of ranges in the ordered collection (possibly using Enumerable.Zip to zip the collection with itself offset by one) and check whether they are adjacent. If not, yield the missing range.
Format an error messages using the missing ranges collected from (3).
e.g.
var ordered = ranges.OrderBy(range => range.Start);
var pairs = ordered.Zip(ordered.Skip(1), (a, b) => new { a, b });
var missing = from pair in pairs
where pair.a.End + 1 < pair.b.Start
select new Range(pair.a.End + 1, pair.b.Start - 1);
An input tolerant solution and the programming Kata used to build it.
public class Range
{
public int End;
public int Start;
public Range(int start, int end)
{
Start = start;
End = end;
}
}
public class RangeGapFinder
{
public Range FindGap(Range range1, Range range2)
{
if (range1 == null)
{
throw new ArgumentNullException("range1", "range1 cannot be null");
}
if (range2 == null)
{
throw new ArgumentNullException("range2", "range2 cannot be null");
}
if (range2.Start < range1.Start)
{
return FindGap(range2, range1);
}
if (range1.End < range1.Start)
{
range1 = new Range(range1.End, range1.Start);
}
if (range2.End < range2.Start)
{
range2 = new Range(range2.End, range2.Start);
}
if (range1.End + 1 >= range2.Start)
{
return null; // no gap
}
return new Range(range1.End + 1, range2.Start - 1);
}
}

Categories