I made an SQL query and filled the data to an ObservableCollection. The database contains many columns so I want to count how many instances where a specific column = 1, then return that number to an int.
The query:
var test = from x in m_dcSQL_Connection.Testheaders
where dtStartTime <= x.StartTime && dtEndtime >= x.StartTime
select new {
x.N,
x.StartTime,
x.TestTime,
x.TestStatus,
x.Operator,
x.Login,
x.DUT_id,
x.Tester_id,
x.PrintID
};
Then I add the data pulled from the database to an Observable Collection via:
lstTestData.Add(new clsTestNrData(item.N.ToString(),
item.StartTime.ToString(),
item.TestTime.ToString()
etc.....
I want to count how many times TestStatus = 1.
I have read about the .Count property but I do not fully understand how it works on ObservableCollections.
Any help?
The standard ObservableCollection<T>.Count property will give you the number of items in the collection.
What you are looking for is this:
testStatusOneItemCount = lstTestData.Where(item => item.TestStatus == 1).Count()
...which uses IEnumerable<T>.Count() method which is part of LINQ.
To elaborate a bit, Count will simply count the objects in your collection.
I suggest having a quick look at linq 101. Very good examples.
Here's an example:
// Assuming you have :
var list = new List<int>{1,2,3,4,5,6 };
var items_in_list = list.Count(); // = 6;
Using linq's Where, you're basically filtering out items, creating a new list. So, the following will give you the count of all the numbers which are pair:
var pair = list.Where(item => item%2 ==0);
var pair_count = pair.Count; // = 3
You can combine this without the temp variables:
var total = Enumerable.Range(1,6).Where(x => x % 2 ==0).Count(); // total = 6;
Or you can then select something else:
var squares_of_pairs = Enumerable.Range(1,6)
.Where(x => x % 2 ==0).
.Select( pair => pair*pair);
// squares_of_pairs = {4,16, 36}. You can count them, but still get 3 :)
Related
I'm trying to convert a SQL expression to Linq but I can't make it work, does anyone help?
SELECT
COUNT(descricaoFamiliaNovo) as quantidades
FROM VeiculoComSeminovo
group by descricaoFamiliaNovo
I try this:
ViewBag.familiasCount = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo).Count();
I need to know how many times each value repeats, but this way it shows me how many distinct values there are in the column.
You can try:
var list = from a in db.VeiculoComSeminovo
group a by a.descricaoFamiliaNovo into g
select new ViewBag{
familiasCount=g.Count()
};
or
var list = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo)
.Select (g => new ViewBag
{
familiasCount=g.Count()
});
If you need column value:
new ViewBag{
FieldName=g.Key,
familiasCount=g.Count()
};
You don't need the GROUP BY unless there are fields other than the one in COUNT. Try
SELECT
COUNT(descricaoFamiliaNovo) as quantidades
FROM VeiculoComSeminovo
UPDATE, from your comment:
SELECT
COUNT(descricaoFamiliaNovo) as quantidades,
descricaoFamiliaNovo
FROM VeiculoComSeminovo
GROUP BY descricaoFamiliaNovo
That's it as SQL. In LINQ it is something like:
var reponse = db.VeiculoComSeminovo.GroupBy(a => a.descricaoFamiliaNovo)
.Select ( n => new
{Name = n.key,
Count = n.Count()
}
)
Not tested.
Ty all for the help.
I solved the problem using this lines:
// get the objects on db
var list = db.VeiculoComSeminovo.ToList();
// lists to recive data
List<int> totaisFamilia = new List<int>();
List<int> totaisFamiliaComSN = new List<int>();
// loop to cycle through objects and add the values I need to their lists
foreach (var item in ViewBag.familias)
{
totaisFamilia.Add(list.Count(a => a.descricaoFamiliaNovo == item && a.valorSeminovo == null));
totaisFamiliaComSN.Add(list.Count(a => a.descricaoFamiliaNovo == item && a.valorSeminovo != null));
}
The query was a little slow than I expected, but I got the data
I have objects from which measurements are saved to a single table. I want to find out how long an object has been in a certain state within a time period.
So in addition to getting the record with the wanted state I need to pair it up with the next measurement made from the same object to calculate the time between them.
I came up with this monster:
// Get the the object entry from Database
MeasuredObject object1;
try
{
object1 = (MeasuredObject)(from getObject in db.MeasuredObject where wantedObject.Id.Equals(getObject.Id) select getObject).Single();
}
catch (System.ArgumentNullException e)
{
throw new System.ArgumentException("Object does not exist", "wantedObject", e);
}
// Get every measurement which matches the state in the time period and the next measurement from it
var pairs = (from m in object1.Measurements
join nextM in object1.Measurements
on (from next in object1.Measurements where (m.Id < next.Id) select next.Id).Min() equals nextM.Id
where 'm is in time period and has required state'
select new { meas = m, next = nextM });
I would say this doesn't seem very efficient especially when I'm using Compact Edition 3.5.
Is there any way to navigate to the next measurement through m or could I somehow use orderby or group to select next by Id? Or even make the join clause simpler?
From the posted code looks like you are working with in memory collection. If that's true, then the following should be sufficient:
var items = (from m in object1.Measurements
where 'm is in time period and has required state'
orderby m.Id
select m)
.ToList();
var pairs = items.Select((item, index) => new
{
meas = item,
next = index + 1 < items.Count ? items[index + 1] : null
});
EDIT: The above is not the exact equivalent of your code because it applies the filter before pairing the items. The exact optimized equivalent would be like this:
var items = object1.Measurements.OrderBy(m => m.Id).ToList();
var pairs = items.Select((item, index) => new
{
meas = item,
next = index + 1 < items.Count ? items[index + 1] : null
})
.Where(pair => 'pair.meas is in time period and has required state');
I can do this in TSQL
SELECT
#TotalDays = COUNT(Days),
#TotalHours = SUM(Hours)
FROM
Schedule
WHERE
GroupID = 1
How to achieve this in linq in single query, my current code;
var totalDays = 0;
var totalHours = 0;
totalDays = _schedule.Count(c => c.GroupID == 1);
totalHours = _schedule.Where(w => w.GroupID == 1).Sum(s => s.Hours);
This is not effective because it call 2 separate queries in the database
You could try something like this:
var result = _schedule.Where(s => s.GroupID == 1)
.GroupBy(x => x.GroupID)
.Select(gr => new
{
TotalDays = gr.Count(),
TotalHours = gr.Sum(s=>s.Hours);
});
Initially, you filter your data based on the GroupID. You pick those with GroupID equals to 1. Then you GroupBy them by their ID. This mihgt seams a bit silly, but this way you create a group of your data. So then you count just count the item in the group and calculate the sum you want. Last but not least after having made the GroupBy, you select an anonymous type with two properties, one for the TotalDays and one for the TotalHours.
Then you can consume the above result as below:
var totalDays = 0;
var totalHours = 0;
var first = result.FirstOrDefault();
if(first!=null)
{
totalDays = first.TotalDays,
totalHours = first.TotalHours
};
The problem, sometimes, trying to make a single LINQ query is that it actually gets translated into multiple database calls. Sometimes it is better to pull all of your raw data into memory in a single database call and then perform the calculations.
This will ensure only one database call:
var data = _schedule.Where(w => w.GroupID == 1).Select(w => w.Hours).ToArray();
var totalDays = data.Count();
var totalHours = data.Sum();
The key to making this work is the .ToArray() which forces the evaluation of the database query. If there are a lot of items this call can become inefficient, but in lot of cases it is still very fast.
You can use the next code
//one request to data base
var lstResult=_schedule.Where(w => w.GroupID == 1).ToArray();
//one loop in array for Count method
totalDays = lstResult.Count();
//One loop in array for Sum method
totalHours = lstResult.Sum(s => s.Hours);
String ss = "lijo is lijom is lijo fdf"; //here two words "is" and "lijo" is repeating two times so my output will be
output : lijo
is
I tried Like this
var count=words.GroupBy(g=>g).Max(k=>k.Count());
//finding the max repeating elements count =2
var res = words.GroupBy(s => s).Where(g => g.Count() == count).Select(s => s);
here i have tried by first finding the max count of repeating words. and assign this value in another query.
i need to know if we can write both this queries together as one query. as a subquery
how to do this in a different way ?
using subquery or any other easy method?
There is an overload of group by that can easily give you your counts.
String ss = "lijo is lijom is lijo fdf";
var words = ss.Split();
var query = words.GroupBy(
word => word,
(key, counts) => new
{
Word = key,
Count = counts.Count()
});
To finish this off, I'd recommend using a MaxBy extension.
Try this:
var l = words.GroupBy(x => x).Select(y => new{key = y.Key, count = y.Count()}).ToList();
var max = l.OrderByDescending(y=>y.count).First().count;
var result = l.Where(x => x.count == max).Select(y=>y.key);
l simply gets the pairs of words and their frequencies. max is the maximum count from l. result will give you the words which have the maximum frequency.
Demo
I have two IList<Traffic> I need to combine.
Traffic is a simple class:
class Traffic
{
long MegaBits;
DateTime Time;
}
Each IList holds the same Times, and I need a single IList<Traffic>, where I have summed up the MegaBits, but kept the Time as key.
Is this possible using Linq ?
EDIT:
I forgot to mention that Time isn't necessarily unique in any list, multiple Traffic instances may have the same Time.
Also I might run into X lists (more than 2), I should had mentioned that as well - sorry :-(
EXAMPLE:
IEnumerable<IList<Traffic>> trafficFromDifferentNics;
var combinedTraffic = trafficFromDifferentNics
.SelectMany(list => list)
.GroupBy(traffic => traffic.Time)
.Select(grp => new Traffic { Time = grp.Key, MegaBits = grp.Sum(tmp => tmp.MegaBits) });
The example above works, so thanks for your inputs :-)
this sounds more like
var store = firstList.Concat(secondList).Concat(thirdList)/* ... */;
var query = from item in store
group item by item.Time
into groupedItems
select new Traffic
{
MegaBits = groupedItems.Sum(groupedItem => groupedItem.MegaBits),
Time = groupedItems.Key
};
or, with your rework
IEnumerable<IList<Traffic>> stores;
var query = from store in stores
from item in store
group item by item.Time
into groupedItems
select new Traffic
{
MegaBits = groupedItems.Sum(groupedItem => groupedItem.MegaBits),
Time = groupedItems.Key
};
You could combine the items in both lists into a single set, then group on the key to get the sum before transforming back into a new set of Traffic instances.
var result = firstList.Concat(secondList)
.GroupBy(trf => trf.Time, trf => trf.MegaBits)
.Select(grp => new Traffic { Time = grp.Key, MegaBits = grp.Sum()});
That sounds like:
var query = from x in firstList
join y in secondList on x.Time equals y.Time
select new Traffic { MegaBits = x.MegaBits + y.MegaBits,
Time = x.Time };
Note that this will join in a pair-wise fashion, so if there are multiple elements with the same time in each list, you may not get the results you want.