I have var t from linq query with this structure:
[0] = { Type = "K", Count = 1 }
[1] = { Type = "Z", Count = 8 }
and now I want to bind it to my chart with elegance (no foreach). I try to do something like this:
series1.Points.DataBindXY(t. ????, t.????);
but I don't know how to get "first column" and "second column" of my var.
Please help
Edit:
My linq query:
var t= (from oAction in Actions
group oAction by oAction.Type.Name into g
select new { Type = g.Key, Count = g.Count() }).ToArray();
I have never worked with ASP.Net charts, so I'm not sure this will work, but I think it should:
series1.Points.DataBindXY(t.Select(x => x.Type), t.Select(x => x.Count));
This will assign a collection of Type values as the x values and collection of Count values as y values.
var t= (from oAction in Actions
group oAction by oAction.Type.Name into g
select new { Type = g.Key, Count = g.Count() }).ToArray();
All-right, so you are returning an "Anonymous" type. You can definitely access t.Type or t.Count but the catch is you can do this only inside the method where this LINQ query is defined. The scope of anonymous type is limited to the method in which it is defined. You can overcome this limitation by using "dynamic" keyword. But I haven't tried this, so can't be 100% sure.
Related
I'm trying to output data like this:
[[...],[...],[...],[...]]
But my query gives me this result:
[{...},{...},{...},{...}]
Here is my query:
var result = (from c in displayedCompanies
group c by new { c.CodigoDeVenta } into s
select new{
ID = Convert.ToString(i++),
s.Key.CodigoDeVenta,
TotalInv = s.Sum(x => x.Inventario)
}).ToArray();
I've tried some options like the following but it's wrong:
var result = (from c in displayedCompanies
group c by new { c.CodigoDeVenta } into s
select new [] {
ID = Convert.ToString(i++),
s.Key.CodigoDeVenta,
TotalInv = s.Sum(x => x.Inventario)
}).ToArray();
Note that the diference is the [] in select new []. I used to have a query before I implemented the "group by" that worked correctly, but after I added the group by this does not work anymore.
Thanks!
Setting aside the grouping, focusing only on the syntax, your anonymous array (new [] {...}) should be fine.
However, it appears that you're trying to assign Id = and TotalInv = which looks like a leftover from the previous revision where you were selecting an anonymous object.
So, instead, you should be able to drop the member identifiers and select just the values you want in the child arrays:
select new [] {
Convert.ToString(i++),
s.Key.CodigoDeVenta,
s.Sum(x => x.Inventario)
}
I have a query that looks like this: it takes a list of IDs (ThelistOfIDs) as parameter and I'm grouping for a count.
var TheCounter = (from l in MyDC.SomeTable
where ThelistOfIDs.Contains(l.ID)
group l by l.Status into groups
select new Counter()
{
CountOnes = (from g in groups
where g.Status == 1
select g).Count(),
CountTwos = (from g in groups
where g.Status == 2
select g).Count(),
}).Single();
And basically, I don't understand why I'm getting the error. I don't want to brring back the entore collection from the DB and do the count in linq-to-object; I want to do the count in the DB and bring back the result.
I have not put your query into my IDE or compiled with C#, but I guess the problem is that
groups in your query is IGrouping<Tkey, Telm> and not IQueryable<Tkey>
(where Tkey is type of l.Status and Telm is type of l).
I think you got confused with the use of grouping operator.
What you want to get is I guess:
var queryByStatus = from l in MyDC.SomeTable
where ThelistOfIDs.Contains(l.ID)
group l by l.Status;
var counter = new Counter()
{
CountOnes = queryByStatus.Where(l => l.Key == 1).Count(),
CountTwos = queryByStatus.Where(l => l.Key == 2).Count(),
};
EDIT:
Alternative query, to obtain the same, moving all operation on DB into the original query so that DB is queried only once.
var queryCountByStatus = from l in MyDC.SomeTable
where ThelistOfIDs.Contains(l.ID)
group l by l.Status into r
select new { status = r.Key, count = r.Count() };
var countByStatus = queryCountByStatus.ToList();
var counter = new Counter()
{
CountOnes = countByStatus.FirstOrDefault(l => l.status == 1).count,
CountTwos = countByStatus.FirstOrDefault(l => l.status == 2).count,
};
Note:
The query in my edit section queries the DB once only and mapping Status -> Count is returned.
Note that in my original query there were two calls to DB needed only - both of which returned single number - one for CountOnes, one for CountTwos.
In the edit query, one query is done which return table { { 1, CountOnes}, {2, CountTwos } }. The other lines are just to convert the result - which is set of items - into single object having certain objects as properties and is done physically on these two values.
You are grouping by Status, and then projecting from that group - but you will still have one row per unique Status (===group).
So: I propose that you don't have exactly one unique Status.
This might be what you're looking for to get...
(it's for users table I had but should be the same)
var statuscounts = (from u in db.Users
where u.UserStatus > 0
group u by u.UserStatus into groups
select new { Status = groups.Key, Count = groups.Count() });
// do this to iterate and pump into a Counter at will
foreach (var g in statuscounts)
Console.WriteLine("{0}, {1}", g.Status, g.Count);
...or even something like this...
var counter = statuscounts.AsEnumerable()
.Aggregate(new Counter(), (c, a) => {
switch (a.Status)
{
case 1: c.CountOfOnes = a.Count; return c;
case 2: c.CountOfTwos = a.Count; return c;
case 3: c.CountOfThrees = a.Count; return c;
default: c.CountOfOthers = a.Count; return c;
}});
...point is that if you're grouping already you should use the grouping result, it's of type IGrouping<out TKey, out TElement> where the key is your status and it's IEnumerable<> or your records.
hope this helps
I have this:
// Load changelog types
ChangeLogType[] Types = ChangeLogFunctions.GetAllChangelogTypes();
foreach(ChangeLogType Rec in Types){
ListItem N = new ListItem();
N.Text = Rec.Type;
N.Value = Rec.ID.ToString();
LstChangeLogType.Items.Add(N);
}
It calls a function that returns an array of ChangeLogTypes, and then adds each one into a list control. Is there a more elegant way of doing this? I feel I'm repeating code each time I do this or something similar.
Yup, LINQ to Objects is your friend:
var changeLogTypes = ChangeLogFunctions.GetAllChangelogTypes()
.Select(x => new ListItem {
Text = x.Type,
Value = x.ID.ToString() })
.ToList();
The Select part is projecting each ChangeLogType to a ListItem, and ToList() converts the resulting sequence into a List<ListItem>.
This is assuming you really wanted a new list with all these entries. If you need to add the results to an existing list, you'd do that without the ToList call, but calling AddRange on an existing list with the result of the Select call.
It's well worth learning more about LINQ in general and LINQ to Objects in particular - it can make all kinds of things like this much simpler.
var range = Types.Select(rec =>
new ListItem { Text = rec.Type, Value = rec.ID.ToString() });
LstChangeLogType.AddRange(range);
Linq?
LstChangeLogType.Items = Types.Select(x => new ListItem()
{ Text = x.Type, Value = x.ID.ToString() }).ToList();
using System.Linq;
var items = Types
.Select (rec => ListItem
{
Text = Rec.Type;
Value = Rec.ID.ToString();
}
LstChangeLogType.Items.AddRange(items);
Using some LINQ extension methods:
LstChangeLogType.AddItems.AddRange(
Types.Select(t =>
new ListItem() { Text = t.Type, Value = t.ID.ToString() }).ToArray());
I have the following code:
var data= from row in table.AsEnumerable()
group row by row.Field<string>("id") into g
select new { Id= g.Key };
I would like to add 1 more element to the data variable. How would I do it? (is there something like a data.Concat(1) etc
If you want to add an additional Id you can indeed concat it:
data = data.Concat( new [] { new { Id= "1" } });
This works because anonymous types that have the same fields in the same order are compiled down to the same type.
You can return the LINQ result as a List<string>.
Generic lists can Add more itens easily.
var data = (from row in table.AsEnumerable()
group row by row.Field<string>("id") into g
select new { Id = g.Key }).ToList();
data.Add(new { Id = "X" });
This way you will not need to declare another variable to hold the Enumerable with the new item (since an Enumerable is imutable and can't add new items to itself).
EDIT:
Like pointed, changing the Enumerable<T> to List<T> will put and hold all the elements on the memory, wich isn't a good performance approach.
To stay with the Enumerable<T>, you can do:
data = data.Concat(new [] { new { Id = "X" } });
Because a Enumerable<Anonymous> can be placed inside itself.
I don't know how with query syntax, but you can use Concat with a single value by creating a new array of values with a single item:
IEnumerable<int> data = GetData()
.Concat(new[] { "5" });
The problem with doing this simply is that your data is an IEnumerable<AnonymousType>, which you can't simply new up, and I don't think new anonymous types are compatible with each other. (Edit: According to BrokenGlass, they are compatible. You can try his solution instead).
If they aren't compatible, you could concat the item before your Select clause, but again, how do you create an item of that type.
The solution would probably be to select to an IEnumerable<string> first, concat, then re-select into your anonymous type:
var data = (from row in table.AsEnumerable()
group row by row.Field<string>("id") into g
select g.Key)
.Concat(new[] { "5" })
.Select(k => new { Id = key });
Or to create a new named structure for your result, and concatenate one of those:
var data = from row in table.AsEnumerable()
group row by row.Field<string>("id") into g
select new MyCustomResult() { Id = g.Key };
data = data.Concat(new MyCustomResult() { Id = "5" });
You would need to change from an anonymous type to a known type and then add that new element.
// ...
select new MyResultClass { Id = g.Key };
data.Add(new MyResultClass { Id = 4 });
I am having a terrible time finding a solution to what I am sure is a simple problem.
I started an app with data in Lists of objects. It's pertinent objects used to look like this (very simplified):
class A {
int[] Nums;
}
and
List<A> myListOfA;
I wanted to count occurrences of values in the member array over all the List.
I found this solution somehow:
var results
from a in myListOfA
from n in a.Nums
group n by n into g
orderby g.Key
select new{ number = g.Key, Occurences = g.Count}
int NumberOfValues = results.Count();
That worked well and I was able to generate the histogram I wanted from the query.
Now I have converted to using an SQL database. The table I am using now looks like this:
MyTable {
int Value1;
int Value2;
int Value3;
int Value4;
int Value5;
int Value6;
}
I have a DataContext that maps to the DB.
I cannot figure out how to translate the previous LINQ statement to work with this. I have tried this:
MyDataContext myContext;
var results =
from d in myContext.MyTable
from n in new{ d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6 }
group n by n into g
orderby g.Key
select new { number = g.Key, Occurences = g.Count() };
I have tried some variations on the constructed array like adding .AsQueryable() at the end - something I saw somewhere else. I have tried using group to create the array of values but nothing works. I am a relative newbie when it come to database languages. I just cannot find any clue anywhere on the web. Maybe I am not asking the right question. Any help is appreciated.
I received help on a microsoft site. The problem is mixing LINQ to SQL with LINQ to Objects.
This is how the query should be stated:
var results =
from d in MyContext.MyTable.AsEnumerable()
from n in new[]{d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6}
group n by n into g
orderby g.Key
select new {number = g.Key, Occureneces = g.Count()};
Works like a charm.
If you wish to use LINQ to SQL, you could try this "hack" that I recently discovered. It isn't the prettiest most cleanest code, but at least you won't have to revert to using LINQ to Objects.
var query =
from d in MyContext.MyTable
let v1 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value1)
let v2 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value2)
// ...
let v6 = MyContext.MyTable.Where(dd => dd.ID == d.ID).Select(dd => dd.Value6)
from n in v1.Concat(v2).Concat(v3).Concat(v4).Concat(v5).Concat(v6)
group 1 by n into g
orderby g.Key
select new
{
number = g.Key,
Occureneces = g.Count(),
};
How about creating your int array on the fly?
var results =
from d in myContext.MyTable
from n in new int[] { d.Value1, d.Value2, d.Value3, d.Value4, d.Value5, d.Value6 }
group n by n into g
orderby g.Key
select new { number = g.Key, Occurences = g.Count() };
In a relational database, such as SQL Server, collections are represented as tables. So you should actually have two tables - Samples and Values. The Keys table would represent a single "A" object, while the Values table would represent each element in A.Nums, with a foreign key pointing to the one of the records in the Samples table. LINQ to SQL
's O/R mapper will then create a "Values" property for each Sample object, which contains a queryable collection of the attached Values. You would then use the following query:
var results =
from sample in myContext.Samples
from value in sample.Values
group value by value into values
orderby values.Key
select new { Value = values.Key, Frequency = values.Count() };