create an array of anonymous type - c#

I am trying to get data from database for Google charts in my program. I would like to create an array of anonymous type (var) instead of repeating my code over and over again:
public JsonResult GetChartData(int sID, int regionID)
{
var testPathOne = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at };
var testPathTwo = from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 2
select new { time = p.time, created_at = p.created_at };
var tOne = testPathOne.ToArray();
var tTwo = testPathTwo.ToArray();
var name = new { test1 = tOne, test2 = tTwo };
return Json(name);
}
i know that i will need a for loop so i can go through all the test path id's instead of hard coding them like this p.test_path_id == 1, but my question is how would i make this part dynamic var name = new { test1 = tOne, test2 = tTwo };
Edit:
I apologize, I would like to do something like this:
name is an array
for loop:
testPath = query
name.Add(testPath)
I hope that makes sense

The easiest solution in this particular case would be to just give a name to the class that is currently anonymous. While there are workarounds that you can use, when you need to start working really hard to use an anonymous type you probably shouldn't be using it. It's there to make certain tasks quicker and easier; if that isn't happening then you are likely better off with a real class.
That solution would look something like this:
//Please give me a real name
public class ClassToBeRenamed
{
public DateTime Time { get; set; }
public DateTime CreatedAt { get; set; }
}
List<ClassToBeRenamed[]> myList = new List<ClassToBeRenamed[]>();
for (int i = 0; i < 10; i++)
{
myList.Add((from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new ClassToBeRenamed { Time = p.time, CreatedAt = p.created_at })
.ToArray());
}
Having said all of that, it's still possible.
var myList = new[]{
from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == 1
select new { time = p.time, created_at = p.created_at }.ToArray()
}.ToList();
for (int i = 2; i < 10; i++)
{
myList.Add(from p in _rep.GetMetricsData().GetLHDb().page_loads
where p.t_3id == sID && p.test_path_id == i
select new { time = p.time, created_at = p.created_at }.ToArray()
);
}
var myArray = myList.ToArray();
If it's really, really important that you have an array, and not a list, then you could call ToArray on myList at the very end. It's important that you start out with a list, and only convert it to an array at the end because Arrays have a fixed size once they are created. You can mutate their contents, but you can't make them bigger or smaller. A List on the other hand, is designed to mutate it's size over time, so it can start out with 0 or 1 items and then add items over time, which is important for us in this particular context. (It's actually useful quite often, which is why it is frequently useful to use List over arrays.)

Instead of using LINQ use foreach loops. You are more limited with LINQ.
Also define your ArrayLists at the beginning and add to them as you go.
var test1 = new ArrayList();
var test2 = new ArrayList();
foreach(PageLoad p in _rep.GetMetricsData().GetLHDb().page_loads)
{
if(p.t_3id == sID)
{
var tr = new { time = p.time, created_at = p.created_at };
switch(p.test_path_id)
{
case 1: test1.Add(tr); break;
case 2: test2.Add(tr); break;
}
}
}
return Json(new { test1, test2, });
You do not need to define the names of properties anonymous types because they default to the variable names.

Related

C# - How to filter list using enum

I have 2 a classes:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
public ArticleApiDto
{
public int Id;
public ArticleType Type;
}
Now i have method for getting data from db, something like:
public List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
res = context.articles.ToList();
//do stuff
}
Now I would like to filter out Articles from res whose type is specified in types from parameter of method.
Problem 1: I actually cant use Contains because ArticleType is enum
Problem 2: List<ArticleType> is because sometimes i want to pass only one type but sometimes two or three. At the moment i cant figure out better better solution.
Can someone help me with this please I was searching for whole noone but cant figure out
To be able to pass more than one type you can do it like:
Make your enum to be Flags (note that values now can't be 1,2,3,4 and should be 1,2,4,8,16,...:
[Flags]
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 4;
}
Now you add up what you want to filter with |:
filter = ArtickeType.News | ArticleType.Service;
var result = res.Where(x => filter & x.Type != 0).ToList();
or:
filter = ArtickeType.News | ArticleType.Service | ArticleType.SpecialOffer;
var result = res.Where(x => filter.HasFlag(x.Type)).ToList();
To do it with your current enum:
public enum ArticleType
{
News = 1;
SpecialOffer = 2;
Service = 3;
}
var filter = new List<ArticleType> { ArticleType.Service, ArticleType.News};
var result = res.Where(x => filter.Contains(x.Type)).ToList();
This code work with me, I use Linq with contains it may solve your problem.
public static List<ArticleApiDto> GetAll(List<ArticleType> types)
{
var res = new List<ArticleApiDto>();
List<ArticleApiDto> articles = new List<ArticleApiDto>
{
new ArticleApiDto{Id = 1, Type = ArticleType.News },
new ArticleApiDto{Id = 2, Type = ArticleType.SpecialOffer },
};
var newArticales = articles.Where(i =>
{
return types.Contains(i.Type);
}).ToList();
return newArticales;
}

Some values in LINQ Query Statement aren't saved correctly to class with subsonic 3

I am developing a MVC 3 Application which uses Subsonic 3 for accessing the database.
My Problem is, i don't understand why the Enum "GlobalType" is not being written into the property.
Everytime i check, the value is 0 instead of "One".
The "Name" property contains the "DateCreated" value.
The "DateCreated" property contains a new DateTime instance.
No other fields, as far as i'm aware of, are doing this.
There is no logic inside of the ViewItemModel, it's just a class with properties.
If i add them after this method manually, everything works.
Maybe someone encountered something similar with subsonic (if it even is subsonic itself, maybe i'm making a mistake)?
I have this method in the Backend:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.HeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new ViewItemModel()
{
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel.ToList();
}
Update:
The GlobalType enum looks like this
public enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
If i add them manually, i changed the return statement for this:
var result = itemModel.ToList();
foreach (var item in result)
{
var headerId = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.HeaderID).FirstOrDefault();
var created = _itemQuery.Where(it => it.ID == item.ID).Select(it => it.DateCreated).FirstOrDefault();
var name = _headerQuery.Where(it => it.ID == headerId).Select(it => it.Name).FirstOrDefault();
item.AnnouncementType = GlobalType.One;
item.Name = name;
item.DateCreated = created;
}
return result;
try sample code:
public int enum GlobalType
{
One = 1,
Two = 2,
Individual = 3
}
//enum value Convert to int or other data type using casting
item.AnnouncementType = (int) GlobalType.One;
//Suppose if condition using
if((GlobalType)item.AnnouncementType==GlobalType.One)
{
//your code
}
Thanks to DaveParsons comment, i managed to create a workaround.
In this case, the code will have to iterate twice through the list of found elements, but won't load the entire table into memory.
Since there is a bug (throwing exception) with creating an anonymous object containing multiple classes like so:
select new { item, header, subItems }
I managed to get all the data needed, by manually assigning what i need like so:
public IEnumerable<ViewItemModel> LoadView(int registratorId)
{
var itemModel = from item in _itemQuery
join header in _headerQuery on item.AnnouncementHeaderID equals header.ID
where header.RegistratorID == registratorId && !(from hidden in _headerHiddenQuery where hidden.ItemID == item.ID && hidden.Type == GlobalType.One && hidden.RegistratorID == registratorId select hidden.ID).Any()
orderby item.ID descending
select new {
Type = GlobalType.One,
ID = item.ID,
Name = header.Name,
DateCreated = header.DateCreated,
TypeOfTransport = header.TypeOfTransport,
TransportType = item.TransportType,
Count = (from subItems in _subItemQuery where subItems.ItemID == item.ID select subItems.ID).Count(),
// For Status
IsArchived = header.IsArchived,
IsCanceled = header.IsCanceled,
Process = header.Process,
End = header.End,
IsPublished = header.IsPublished,
OpenFrom = header.OpenFrom,
OpenTill = header.OpenTill,
IsNextStarted = header.IsNextStarted
};
return itemModel
.ToList()
.Select(it => new ViewItemModel() {
Type = it.Type,
ID = it.ID,
Name = it.Name,
DateCreated = it.DateCreated,
TypeOfTransport = it.TypeOfTransport,
TransportType = it.TransportType,
Count = it.Count,
// For Status
IsArchived = it.IsArchived,
IsCanceled = it.IsCanceled,
Process = it.Process,
End = it.End,
IsPublished = it.IsPublished,
OpenFrom = it.OpenFrom,
OpenTill = it.OpenTill,
IsNextStarted = it.IsNextStarted
})
.ToList();
}
Notice: The return value of the query is an anonymous object with every single necessary field declared.
After the database returned all fields with the same name as in the database (model), we then have to force execution with ".ToList()" or something similar (deferred execution?).
Since the data is now in memory, we can assign the values from the anonymous object to the original class that was intended for this purpose.
I am sure there is a more reliable way using reflection, but this is what i have come up with.

Sort list given a list of keys?

I have a List<Project>
A Project has an ID which is an int.
I then have a list of int which is correspond to IDs of projects.
The projects need to be processed in the order of the list of int.
There might be projects with a null ID.
Any project not having an ID or have an id not in the list will go to the bottom (or even better, be removed from the results lists).
I can think of an O(N^2) way to do this but I am wondering if there might be a better way with LINQ or something that could be more m + n or n or something...
Thanks
class Project
{
public int? id;
public Project(int? iid) { id = iid; }
}
public class Program
{
static void Main(string[] args)
{
List<Project> pros = new List<Project>() { new Project(null), new Project(10), new Project(50), new Project(1), new Project(null) };
var x = new Comparison<Project>((Project r, Project l) =>
{
if (r.id == null && l.id == null)
return 0;
if (r.id == null)
{
return 1;
}
if (l.id == null)
{
return -1;
}
return Math.Sign(r.id.Value - l.id.Value);
});
pros.Sort(x);
Console.ReadLine();
}
}
You can change who minuses who and the polarity of -1 or 1 to get the nans where you want it to go. This one pushes the nans to the end and sorts smallest to largest.
Alternatively, if you don't want to process the nans at all and don't want to sort by ID, just use a where statement to get the iterator without the null ids:
var nonulls = pros.Where(pr => (pr.id != null));
Which lazily evaluates as just the set without the nulls, doesn't actually store the intermediates so you don't have to worry about the storage issues. O(N), little to no overhead.
With next solution projects with null Id will be ignored. O(N)
int[] ids = new int[10];
List<Project> projects = new List<Project>();
var projectsDictionary = projects.ToDictionary(proj=> proj.Id, proj => proj);
var orderedProjects = ids.Select(id => projectsDictionary[id]);
Use a custom comparison to handle the null project numbers any way you like:
class Project {
int? ID { get; set; }
}
...
Comparison<Project> comparison = delegate(Project x, Project y)
{
int xkey = x.ID.HasValue ? x.ID.Value : int.MaxValue;
int ykey = y.ID.HasValue ? y.ID.Value : int.MaxValue;
return xkey.CompareTo(ykey);
};
list.Sort(comparison);
Here's a very simple LINQ way to do it. Not sure about the runtime though.
List<int?> pids = new List<int?>() { 2, 4, 3 };
List<Project> projects = new List<Project>() {
new Project(1), new Project(2),
new Project(3), new Project(4),
new Project(5), new Project(null) };
List<Project> sortedProjectsByPids = pids
.Select(pid => projects.First(p => p.ID == pid))
.ToList<Project>();
Assuming your Project class looks like the following:
class Project
{
public int? ID;
public Project(int? id)
{
ID = id;
}
}
Hope this helps!

Creating a two-dimensional array

I am trying to create a two dimensional array and I am getting so confused. I was told by a coworker that I need to create a dictionary within a dictionary for the array list but he couldn't stick around to help me.
I have been able to create the first array that lists the the programs like this
+ project 1
+ project 2
+ project 3
+ project 4
The code that accomplishes this task is below-
var PGList = from x in db.month_mapping
where x.PG_SUB_PROGRAM == SP
select x;
//select x.PG.Distinct().ToArray();
var PGRow = PGList.Select(x => new { x.PG }).Distinct().ToArray();
So that takes care of my vertical array and now I need to add my horizontal array so that I can see the total amount spent in each accounting period. So the final output would look like this but without the dashes of course.
+ program 1-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 2-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 3-------100---200---300---400---500---600---700---800---900---1000---1100---1200
+ program 4-------100---200---300---400---500---600---700---800---900---1000---1100---1200
I have tried to use a foreach to cycle through the accounting periods but it doesn't work. I think I might be on the right track and I was hoping SO could provide some guidance or at the very least a tutorial for me to follow. I have posted the code that I written so far on the second array below. I am using C# and MVC 3. You might notice that their is no dictionary within a dictionary. If my coworker is correct how would I do something like that, I took a look at this question using dictionary as a key in other dictionary but I don't understand how I would use it in this situation.
Dictionary<string, double[]> MonthRow = new Dictionary<string, double[]>();
double[] PGContent = new double[12];
string lastPG = null;
foreach (var item in PGRow)
{
if (lastPG != item.PG)
{
PGContent = new double[12];
}
var MonthList = from x in db.Month_Web
where x.PG == PG
group x by new { x.ACCOUNTING_PERIOD, x.PG, x.Amount } into pggroup
select new { accounting_period = pggroup.Key.ACCOUNTING_PERIOD, amount = pggroup.Sum(x => x.Amount) };
foreach (var P in MonthList)
{
int accounting_period = int.Parse(P.accounting_period) - 1;
PAContent[accounting_period] = (double)P.amount;
MonthRow[item.PG] = PGContent;
lastPG = item.PG;
}
I hope I have clearly explained my issue, please feel free to ask for any clarification needed as I need to solve this problem and will be checking back often. Thanks for your help!
hope this helps.
// sample data
var data = new Dictionary<string, List<int>>();
data.Add("program-1", new List<int>() { 100, 110, 130 });
data.Add("program-2", new List<int>() { 200, 210, 230 });
data.Add("brogram-3", new List<int>() { 300, 310, 330 });
// query data
var newData = (from x in data
where x.Key.Contains("pro")
select x).ToDictionary(v => v.Key, v=>v.Value);
// display selected data
foreach (var kv in newData)
{
Console.Write(kv.Key);
foreach (var val in kv.Value)
{
Console.Write(" ");
Console.Write(val.ToString());
}
Console.WriteLine();
}
output is:
program-1 100 110 130
program-2 200 210 230
Don't try to use anonymous types or LINQ projection to create new data types, especially if you're a beginner, you will just get confused. If you want a specialized data type, define one; e.g.:
public class Account
{
public string Name { get; private set; }
public decimal[] MonthAmount { get; private set; }
readonly int maxMonths = 12;
public Account(string name, ICollection<decimal> monthAmounts)
{
if (name == null)
throw new ArgumentNullException("name");
if (monthAmounts == null)
throw new ArgumentNullException("monthAmounts");
if (monthAmounts.Count > maxMonths)
throw new ArgumentOutOfRangeException(string.Format(" monthAmounts must be <= {0}", maxMonths));
this.Name = name;
this.MonthAmount = new decimal[maxMonths];
int i = 0;
foreach (decimal d in monthAmounts)
{
this.MonthAmount[i] = d;
i++;
}
}
}
Use instances of this type directly, you do not have to convert them to arrays, dictionaries, lists, or anything else:
var accountPeriods = new List<Account>();
accountPeriods.Add(new Account("program-1", new decimal[] { 1, 2, 3, 4 }));
You can use LINQ or whatever to query or alter instances of your new type:
foreach (Account a in accountPeriods)
foreach (decimal d in a.MonthAmount)
DoSomethingWith(d);
That should be enough to get you started.
I want to thank #Ray Cheng and #Dour High Arch for their help but I have figured out another way to accomplish this task and I wanted to post my code so that the next person that is having the same trouble can figure out their problem faster.
Above I split my code into more managable sections to explain my problem as clearly as I could and the code below has all those parts combined so you can see the big picture. This code returns an array that contains the program and the amounts for every month.
public virtual ActionResult getAjaxPGs(string SP = null)
{
if (SP != null)
{
var PGList = from x in db.month_mapping
where x.PG_SUB_PROGRAM == SP
select x;
var PGRow = PGList.Select(x => new { x.PG }).Distinct().ToArray();
float[] PGContent = new float[12];
Dictionary<string,float[]> MonthRow = new Dictionary<string, float[]>();
foreach (var item in PGRow)
{
PGContent = new float[12];
var MonthList = from x in db.month_Web
where x.PG == item.PG
group x by new { x.ACCOUNTING_PERIOD, x.PG, x.Amount } into pggroup
select new { accounting_period = pggroup.Key.ACCOUNTING_PERIOD, amount = pggroup.Sum(x => x.Amount) };
foreach (var mon in MonthList)
{
int accounting_period = int.Parse(mon.accounting_period) - 1;
PGContent[accounting_period] = (float)mon.amount/1000000;
}
MonthRow[item.PG] = PGContent;
}
return Json(MonthRow, JsonRequestBehavior.AllowGet);
}
return View();
}
This code worked great for me since I am pulling from a Linq to SQL query instead of adding data directly into the code. My problems stemmed from mainly putting the data pulls outside of the foreach loops so it only pulled 1 piece of data from the SQL instead of all twelve months. I hope this helps some one else who is trying to pull data in from SQL data sources into multidimensional arrays.

Remove 3 oldest elements from a List<> in C#

Let's say I have an object:
public class CustomObj
{
DateTime Date { get; set; }
String Name { get; set; }
}
Then let's say I have a List with 20 various elements.
var stuff = new List<CustomObj>
{
{ Date = DateTime.Now, Name = "Joe" },
{ Date = DateTime.Now.AddDays(1), Name = "Joe2" },
{ Date = DateTime.Now.AddDays(2), Name = "Joe3" },
{ Date = DateTime.Now.AddDays(3), Name = "Joe4" },
{ Date = DateTime.Now.AddDays(4), Name = "Joe5" },
{ Date = DateTime.Now.AddDays(5), Name = "Joe6" },
{ Date = DateTime.Now.AddDays(6), Name = "Joe7" },
{ Date = DateTime.Now.AddDays(7), Name = "Joe8" },
{ Date = DateTime.Now.AddDays(8), Name = "Joe9" },
{ Date = DateTime.Now.AddDays(9), Name = "Joe10" },
{ Date = DateTime.Now.AddDays(10), Name = "Joe11" }
}
How can I remove the 3 oldest elements?
stuff.RemoveAll(item => ???)
If you only need to enumerate the items, this will work:
stuff.OrderBy(item => item.Date).Skip(3);
If you actually want it in list form you will have to call .ToList() afterwards:
stuff = stuff.OrderBy(item => item.Date).Skip(3).ToList();
If you're willing to replace the list with a new one, you could try this:
stuff = stuff.OrderBy( c => c.Date).Skip(3).ToList();
On the other hand, if you need stuff to remain the same exact List<T> instance, you could sort it and then remove a range by index:
stuff.Sort(...);
stuff.RemoveRange(0, 3);
If your list is ordered you could simply use the RemoveRange method:
int n = 3;
stuff.RemoveRange(stuff.Count - n, n);
const int cToRemove = 3;
var top3 = (from c in stuff
orderby c.Date ascending
select c).Take(cToRemove);
All the other answers so far have relied on sorting the list, which is an O(n log n) operation if you don't already have it sorted.
Here's a solution which is O(n) albeit it with a horrible constant factor. It uses MinBy from MoreLINQ - you could easily rewrite that in your own code if you need to, and even make it return the index directly instead of the value (and useRemoveAt instead of Remove).
// The list.Count part is in case the list starts off with
// fewer than 3 elements
for (int i = 0; i < 3 && list.Count > 0; i++)
{
var oldest = list.MinBy(x => x.Date);
list.Remove(oldest);
}
You could certainly write this more efficiently to find the oldest three elements in a single pass of the list - but the code would be significantly more complicated, leading to more chances for errors. The above should work fine in O(n), even if it's lacking in elegance when you think of it going through the list 6 times :)

Categories