c# add to list<DateCount> - DateTime Best way - c#

I have a list of dates (currently there are 4000 in the selected result)
I am trying to put the results in a chart,
The Class looks like this
public class DisplayObjectDates
{
public int Month { get; set; }
public int Year { get; set; }
public int day { get; set; }
public DateTime fulldatetime { get; set; }
public int CountedDate { get; set; }
}
I have a list of the class
private static List<DisplayObjectDates> SortedDatesDays = new List<DisplayObjectDates>();
and I add to the list like this after calling from EF and getting a returned list
if (SortedDatesDays.Count() == 0)
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.Year = contextreturned.change_time.Year;
addDisplayObjectDatesYear.Month = contextreturned.change_time.Month;
addDisplayObjectDatesYear.day = contextreturned.change_time.Day;
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
else
{
foreach (var VARIABLE in SortedDatesDays)
{
if (VARIABLE.day == contextreturned.change_time.Day && VARIABLE.Month == contextreturned.change_time.Month && VARIABLE.Year == contextreturned.change_time.Year)
{
VARIABLE.CountedDate = VARIABLE.CountedDate++;
}
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.Year = contextreturned.change_time.Year;
addDisplayObjectDatesYear.Month = contextreturned.change_time.Month;
addDisplayObjectDatesYear.day = contextreturned.change_time.Day;
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
}
}
This gives me an error
Collection was modified; enumeration operation may not execute.
so I change the
foreach (var VARIABLE in SortedDatesDays)
to
foreach (var VARIABLE in SortedDatesDays.ToList())
and now i get out of memory exeption
At the end of the day I need to count how many times an event happened on a certain date
I need to put this into a form that i can then use in a chart (DEVEXPRESS)
I am not sure if i should use linq or the current system.
All out of ideas any help with the corrent way in doing this would be greatly appreciated
thanks
a0011010011

I actually thought that foreach (var VARIABLE in SortedDatesDays.ToArray()) will solve the problem as I use it often.
In that case, try the following.
...
else
{
// create a temporary collection for storing new items
var list = new List<DisplayObjectDates>();
foreach (var VARIABLE in SortedDatesDays)
{
if (...) { ... }
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
...
// place it to the new list instead
list.Add(addDisplayObjectDatesYear);
}
}
// merge lists
SortedDatesDays.AddRange(list);
}

While you are assigning FullDateTime DisplayObjectDates object ... I prefer to say you to reconstruct your class it may be something like this ... it also help your program to use less memery ..
public class DisplayObjectDates
{
public int Month { get { return fulldatetime.Month; } }
public int Year { get { return fulldatetime.Year; } }
public int day { get { return fulldatetime.Day; } }
public DateTime fulldatetime { get; set; }
public int CountedDate { get; set; }
}
Then sort your initializing function
if (SortedDatesDays.Count() == 0)
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
else
{
foreach (var VARIABLE in SortedDatesDays)
{
if (VARIABLE.fulldatetime.Date == contextreturned.change_time.fulldatetime.Date)
{
VARIABLE.CountedDate = VARIABLE.CountedDate++;
}
else
{
var addDisplayObjectDatesYear = new DisplayObjectDates();
addDisplayObjectDatesYear.fulldatetime = contextreturned.change_time;
addDisplayObjectDatesYear.CountedDate = 1;
SortedDatesDays.Add(addDisplayObjectDatesYear);
}
}
}

Related

c# how to access all instances of a class outside of the function?

I am new to C# and OOP, in general, I've kinda hit a wall I am reading in this CSV using the CSV Helper package, but there are some unwanted rows, etc so I have cleaned it up by iterating over "records" and creating a new class LineItems.
But Now I appear to be a bit stuck. I know void doesn't return anything and is a bit of a placeholder. But How can I access all the instances of LineItems outside of this function?
public void getMapper()
{
using (var StreamReader = new StreamReader(#"D:\Data\Projects\dictUnitMapper.csv"))
{
using (var CsvReader = new CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
var records = CsvReader.GetRecords<varMapper>().ToList();
foreach (var item in records)
{
if (item.name != "#N/A" && item.priority != 0)
{
LineItems lineItem = new LineItems();
lineItem.variableName = item.Items;
lineItem.variableUnit = item.Unit;
lineItem.variableGrowthCheck = item.growth;
lineItem.variableAVGCheck = item.avg;
lineItem.variableSVCheck = item.svData;
lineItem.longName = item.name;
lineItem.priority = item.priority;
}
}
}
}
}
public class LineItems
{
public string variableName;
public string variableUnit;
public bool variableGrowthCheck;
public bool variableAVGCheck;
public bool variableSVCheck;
public string longName;
public int priority;
}
public class varMapper
{
public string Items { get; set; }
public string Unit { get; set; }
public bool growth { get; set; }
public bool avg { get; set; }
public bool svData { get; set; }
public string name { get; set; }
public int priority { get; set; }
}
You should write your method to return a list.
public List<LineItems> GetMapper()
{
using (var StreamReader = new StreamReader(#"D:\Data\Projects\dictUnitMapper.csv"))
{
using (var CsvReader = new CsvHelper.CsvReader(StreamReader, CultureInfo.InvariantCulture))
{
return
CsvReader
.GetRecords<varMapper>()
.Where(item => item.name != "#N/A")
.Where(item => item.priority != 0)
.Select(item => new LineItems()
{
variableName = item.Items,
variableUnit = item.Unit,
variableGrowthCheck = item.growth,
variableAVGCheck = item.avg,
variableSVCheck = item.svData,
longName = item.name,
priority = item.priority,
})
.ToList();
}
}
}
Here's an alternative syntax for building the return value:
return
(
from item in CsvReader.GetRecords<varMapper>()
where item.name != "#N/A"
where item.priority != 0
select new LineItems()
{
variableName = item.Items,
variableUnit = item.Unit,
variableGrowthCheck = item.growth,
variableAVGCheck = item.avg,
variableSVCheck = item.svData,
longName = item.name,
priority = item.priority,
}
).ToList();

Map one class data to another class with iteration

I have a C# project and looking for simple solution for map one class object data to list of another class object.
This is my input class
public class RatesInput
{
public string Type1 { get; set; }
public string Break1 { get; set; }
public string Basic1 { get; set; }
public string Rate1 { get; set; }
public string Type2 { get; set; }
public string Break2 { get; set; }
public string Basic2 { get; set; }
public string Rate2 { get; set; }
public string Type3 { get; set; }
public string Break3 { get; set; }
public string Basic3 { get; set; }
public string Rate3 { get; set; }
}
This is my another class structure
public class RateDetail
{
public string RateType { get; set; }
public decimal Break { get; set; }
public decimal Basic { get; set; }
public decimal Rate { get; set; }
}
it has a object like below. (For easiering the understanding, I use hardcoded values and actually values assign from a csv file)
RatesInput objInput = new RatesInput();
objInput.Type1 = "T";
objInput.Break1 = 100;
objInput.Basic1 = 50;
objInput.Rate1 = 0.08;
objInput.Type2 = "T";
objInput.Break2 = 200;
objInput.Basic2 = 50;
objInput.Rate2 = 0.07;
objInput.Type3 = "T";
objInput.Break3 = 500;
objInput.Basic3 = 50;
objInput.Rate3 = 0.06;
Then I need to assign values to "RateDetail" list object like below.
List<RateDetail> lstDetails = new List<RateDetail>();
//START Looping using foreach or any looping mechanism
RateDetail obj = new RateDetail();
obj.RateType = //first iteration this should be assigned objInput.Type1, 2nd iteration objInput.Type2 etc....
obj.Break = //first iteration this should be assigned objInput.Break1 , 2nd iteration objInput.Break2 etc....
obj.Basic = //first iteration this should be assigned objInput.Basic1 , 2nd iteration objInput.Basic2 etc....
obj.Rate = //first iteration this should be assigned objInput.Rate1, 2nd iteration objInput.Rate2 etc....
lstDetails.Add(obj); //Add obj to the list
//END looping
Is there any way to convert "RatesInput" class data to "RateDetail" class like above method in C#? If yes, how to iterate data set?
Try this:
public class RatesList : IEnumerable<RateDetail>
{
public RatesList(IEnumerable<RatesInput> ratesInputList)
{
RatesInputList = ratesInputList;
}
private readonly IEnumerable<RatesInput> RatesInputList;
public IEnumerator<RateDetail> GetEnumerator()
{
foreach (var ratesInput in RatesInputList)
{
yield return new RateDetail
{
RateType = ratesInput.Type1,
Break = Convert.ToDecimal(ratesInput.Break1, new CultureInfo("en-US")),
Basic = Convert.ToDecimal(ratesInput.Basic1, new CultureInfo("en-US")),
Rate = Convert.ToDecimal(ratesInput.Rate1, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type2,
Break = Convert.ToDecimal(ratesInput.Break2),
Basic = Convert.ToDecimal(ratesInput.Basic2),
Rate = Convert.ToDecimal(ratesInput.Rate2, new CultureInfo("en-US"))
};
yield return new RateDetail
{
RateType = ratesInput.Type3,
Break = Convert.ToDecimal(ratesInput.Break3),
Basic = Convert.ToDecimal(ratesInput.Basic3),
Rate = Convert.ToDecimal(ratesInput.Rate3, new CultureInfo("en-US"))
};
}
}
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
}
And use:
var list = new RatesList(new List<RatesInput>() { objInput });
foreach (var item in list)
{
Console.WriteLine(item.Basic);
}
You can use Reflection to get the properties info like this:
var props = objInput.GetType().GetProperties();
var types = props.Where(x => x.Name.StartsWith("Type"))
.Select(x => x.GetValue(objInput)).ToList();
var breaks = props.Where(x => x.Name.StartsWith("Break"))
.Select(x => x.GetValue(objInput)).ToList();
var basics = props.Where(x => x.Name.StartsWith("Basic"))
.Select(x => x.GetValue(objInput)).ToList();
var rates = props.Where(x => x.Name.StartsWith("Rate"))
.Select(x => x.GetValue(objInput)).ToList();
List<RateDetail> lstDetails = new List<RateDetail>();
for (int i = 0; i < types.Count; i++)
{
lstDetails.Add(new RateDetail
{
RateType = types[i].ToString(),
Break = Convert.ToDecimal(breaks[i]),
Basic = Convert.ToDecimal(basics[i]),
Rate = Convert.ToDecimal(rates[i])
});
}

Getting value of next row while iterating through rows

myClass structure :
public class myClass
{
public string Name { get; set; }
public string AdditionalData { get; set; }
public System.DateTime ActivityTime { get; set; }
}
I have a list of the above class List all ordered by ActivityTime say 'acts'.
I wish to convert my data to a list of following class..
public class newClass
{
public string Name { get; set; }
public string AdditionalData { get; set; }
public System.DateTime StartTime { get; set; }
public System.DateTime EndTime { get; set; }
}
Here StartTime will have the same value as the prev class's ActivityTime and so I do not have a problem.
But EndTime should have the ActivityTime value of next list object, this I'm unable to figure how to get..
The last list object's EndTime can be same as starttime
so my code is ..
List<newClass> items = new List<newClass>();
foreach (var item in acts)
{
newClass si = new newClass
{
Name=item.Name,
AdditionalData=item.AdditionalData,
StartTime = item.ActivityTime ,
EndTime = //what do I do here??????
};
items.Add(si);
}
Any help is sincerely appreciated
It's not possible to access the next iterator value until moving to that position.
What you can do here is to remember the previous item and update it in the next loop. Assuming that for the last element it should be empty it will look like this:
List<newClass> items = new List<newClass>();
newClass last = null;
foreach (var item in acts) {
// update the last element here:
if (last != null)
last.EndTime = item.ActivityTime;
newClass si = new newClass
{
Name=item.Name,
AdditionalData=item.AdditionalData,
StartTime = item.ActivityTime ,
//EndTime = null; // will be updated in the next loop
};
last = si;
items.Add(si);
}
// handle the last item (if needed):
if (last != null)
last.EndTime = ... // special value for last item
I have a much elegant solution than for-loop:
List<newClass> output = acts.Select((a, index) => new newClass()
{
Name = a.Name,
AdditionalData = a.AdditionalData,
StartTime = a.ActivityTime,
EndTime = (index + 1 < acts.Count) ? acts[index + 1].ActivityTime : default(DateTime)
}).ToList();
Or you can use a for loop instead of foreach:
List<newClass> items = new List<newClass>();
// assuming length > 0
int length = (acts.Length % 2 == 0) ? acts.Length : acts.Length - 1;
for (int i = 0; i < acts.Length; i++)
{
newClass si = new newClass
{
Name=acts[i].Name,
AdditionalData=acts[i].AdditionalData,
StartTime = acts[i].ActivityTime ,
EndTime = acts[i+1].ActivityTime
};
items.Add(si);
}
if (length < acts.Length)
// handle the last element as you wish
If you want to use LINQ you can create an extension method such as...
public static class EnumerableEx
{
public static IEnumerable<Tuple<T, T>> WithNext<T>(this IEnumerable<T> items)
{
var e = items.GetEnumerator();
bool r = e.MoveNext();
if (!r)
yield break;
do
{
T last = e.Current;
var item = (r = e.MoveNext()) ? e.Current : default(T);
yield return Tuple.Create(last, item);
} while (r);
}
}
... here is an example on how to use it ...
class Program
{
static void Main(string[] args)
{
var i = new int?[] { 1, 2, 3 };
foreach (var n in i.WithNext())
//the last value will be paired with a null.
// you can use null coalesce to fill in the missing item.
Console.WriteLine("{0} => {1}", n.Item1, n.Item2 ?? 9);
/*
1 => 2
2 => 3
3 => 9
*/
}
}

The specified table does not exist[entity]

I have spent hours trying to figure out why my database cannot find the table I have found numerous examples and none have seemed to help. I have created a separate class to handle the database operations so I can use it on multiple pages.
Here is the code
[Table]
public class MatchItem
{
[Column(IsPrimaryKey = true, CanBeNull=false,IsDbGenerated=true)]
public int MatchID { get; set; }
[Column(CanBeNull = false)]
public string MatchNumber { get; set; }
[Column(CanBeNull = false)]
public string EventName { get; set; }
[Column(CanBeNull = false)]
public DateTime Time { get; set; }
[Column(CanBeNull = false)]
public string[] RedTeams { get; set; }
[Column(CanBeNull = false)]
public string[] BlueTeams { get; set; }
[Column(CanBeNull = false)]
public int RedFinal { get; set; }
[Column(CanBeNull = false)]
public int BlueFinal{ get; set; }
}
Here is the Data context
public class MatchDataContext:DataContext
{
public MatchDataContext(string connectionString) :
base(connectionString)
{
}
public Table<MatchItem> Matches
{
get
{
return this.GetTable<MatchItem>();
}
}
}
I made a class so I could use it on multiple pages
public class MatchDBManager
{
private static string connectionString = #"Data Source=isostore:/DB.sdf";
public MatchDBManager()
{
initialize();
}
public void initialize()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Console.WriteLine("DB already exists");
}
else
{
Mchdb.CreateDatabase();
Console.WriteLine("DB created");
}
}
}
public void addMatchData(IList<MatchItem> data)
{
//this.clearData();
//initialize();
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
Mchdb.Matches.InsertAllOnSubmit(data);
Mchdb.SubmitChanges();
}
}
public IList<MatchItem> getTeamData(string teamNum)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where (mch.RedTeams[0] == teamNum || mch.RedTeams[1] == teamNum || mch.RedTeams[2] == teamNum || mch.BlueTeams[0] == teamNum || mch.BlueTeams[1] == teamNum || mch.BlueTeams[2] == teamNum) select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
public IList<MatchItem> getEventData(string eventID)
{
IList<MatchItem> MatchList = null;
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
IQueryable<MatchItem> mchQuery = from mch in Mchdb.Matches where mch.Event == eventID select mch;
MatchList = mchQuery.ToList();
}
return MatchList;
}
private void clearData()
{
using (MatchDataContext Mchdb = new MatchDataContext(connectionString))
{
if (Mchdb.DatabaseExists())
{
Mchdb.DeleteDatabase();
}
}
}
}
I have the error The specified table does not exist[Match].
Added here is where I download
public IList<MatchItem> ParseXML(XmlReader reader)
{
//List<string> save = new List<string>();
List<MatchItem> MatchList= new List<MatchItem>();
XElement matchData;
matchData = XElement.Load(reader);
StringBuilder output = new StringBuilder();
int count = 0;
var matches = from item
in matchData.Elements("match")
select item;
foreach (XElement eachmatch in matches)
{
MatchItem mch = new MatchItem();
string Time = ((eachmatch.Element("pubdate").Value).ToString());
mch.EventName = ((eachmatch.Element("event").Value).ToString());
mch.MatchNumber = ((eachmatch.Element("mch").Value).ToString() + (eachmatch.Element("typ").Value).ToString());
string[] RT = { eachmatch.Element("red1").Value.ToString(), eachmatch.Element("red2").Value.ToString(), eachmatch.Element("red3").Value.ToString() };
string[] BT = { eachmatch.Element("blue1").Value.ToString(), eachmatch.Element("blue2").Value.ToString(), eachmatch.Element("blue3").Value.ToString() };
string RF = ((eachmatch.Element("rfin").Value).ToString());
string BF = ((eachmatch.Element("bfin").Value).ToString());
// Time = Time.Substring(0, (Time.IndexOf("+") - 1));
mch.Time = DateTime.Parse(Time);
mch.RedTeams = RT;
mch.BlueTeams = BT;
mch.RedFinal = int.Parse(RF);
mch.BlueFinal= int.Parse(BF);
mch.MatchID = count;
count += 1;
MatchList.Add(mch);
}
return MatchList;
}
This is where I call this method
void client_DownloadStringCompleted(object sender, DownloadStringCompletedEventArgs e)
{
initializeDB();
if (e.Error == null)
{
XmlReader reader = XmlReader.Create(new StringReader(e.Result));
DownloadInfo di = new DownloadInfo();
IList <MatchItem>data= di.ParseXML(reader);
outputer(data);
addData(data.ToList<MatchItem>());
}
else
{
IList<MatchItem> data = getTeamData(strMyTeam);
outputer(data);
}
}
I ended up removing the DatabaseManager class and putting the functions in the main code
Then I output them to the screen here
public void outputer(IList<MatchItem> mch)
{
for (int i = 0; i < mch.Count; i++)
{
Score sc = new Score();
sc.Width = lsbData.Width;
sc.Height = sc.Height;
sc.Time = mch[i].Time.ToString();
sc.Event = mch[i].EventName;
sc.RT = mch[i].RedTeams[0] + " " + mch[i].RedTeams[1] + " " + mch[i].RedTeams[2];
sc.BT = mch[i].BlueTeams[0] + " " + mch[i].BlueTeams[1] + " " + mch[i].BlueTeams[2];
sc.RF = mch[i].RedFinal.ToString();
sc.BF = mch[i].BlueFinal.ToString();
lsbData.Items.Add(sc);
}
}
*note:score is a custom control that works(and worked) before the database code *
I don't see where you actually create a Match Object.
if you have you need to include that code in the question as well. and if you haven't, that would explain why it doesn't exist.
Addition
in order to add Match Objects to a list you will have to create the objects first then add them to the list, I don't think you can create the whole list of objects before creating each individual object.
more Additional Information
the object still needs to be created before you can add items to it. that is what the error is telling you. you don't have the object to insert data into.
Match Table1 = new Match();
this creates a new Match object which allows you to access the pieces of the object and insert data into the object like this
Table1.MatchNumber = 42
you can't add to something to a memory location until you set aside that memory location for that specific person and give it a name.
when you create that class you can add functions and all sorts of fun stuff to it, but you can't use any of it until you have created a Match Object.
you can't add something to a list that doesn't exist, you have to create the Match Object first, then add it to the list

How do I Find an object up the list I am iterating through

I am iterating through a List of objects of Type "prvEmployeeIncident".
The object has the following properties:
public DateTime DateOfIncident { get; set; }
public bool IsCountedAsAPoint;
public decimal OriginalPointValue;
public bool IsFirstInCollection { get; set; }
public bool IsLastInCollection { get; set; }
public int PositionInCollection { get; set; }
public int DaysUntilNextPoint { get; set; }
public DateTime DateDroppedBySystem { get; set; }
public bool IsGoodBehaviorObject { get; set; }
My List is sorted by the DateOfIncident property. I would like to find the next object up the list where IsCounted == true and change it to IsCounted = false.
One question:
1) How do I find this object up the list ?
If I understand your question correctly, you can use LINQ FirstOrDefault:
var nextObject = list.FirstOrDefault(x => x.IsCountedAsAPoint);
if (nextObject != null)
nextObject.IsCountedAsAPoint = false;
If I understand correctly this can be solved with a simple foreach loop. I don't exactly understand your emphasis on "up" as you don't really move up a list, you traverse it. Anyways, the following code snippet finds the first Incident where IsCounted is true and changes it to false. If you're starting from a given position change the for each loop to a for loop and start at i = currentIndex with the exit condition being i < MyList.Count. Leave the break statement to ensure you only modify one Incident object.
foreach (prvEmployeeIncident inc in MyList)
{
if (inc.IsCountedAsAPoint)
{
inc.IsCountedAsAPoint = false;
break;
}
}
You can use List(T).FindIndex to search up the list.
Example:
public class Foo
{
public Foo() { }
public Foo(int item)
{
Item = item;
}
public int Item { get; set; }
}
var foos = new List<Foo>
{
new Foo(1),
new Foo(2),
new Foo(3),
new Foo(4),
new Foo(5),
new Foo(6)
};
foreach (var foo in foos)
{
if(foo.Item == 3)
{
var startIndex = foos.IndexOf(foo) + 1;
var matchedFooIndex = foos.FindIndex(startIndex, f => f.Item % 3 == 0);
if(matchedFooIndex >= startIndex) // Make sure we found a match
foos[matchedFooIndex].Item = 10;
}
}
Just be sure you do not modify the list itself since that will throw an exception.

Categories

Resources