I have a list that contains only strings. What I would love to do is group by and return a count.
For instance:
Foo1
Foo2
Foo3
Foo1
Foo2
Foo2
Would result in Foo1: 2, Foo2: 3, Foo3: 1. I've tried with Linq but the list has a GroupBy that might do the trick but i messed it up, can't figure the use :(
var list = new List<string> { "Foo1", "Foo2", "Foo3", "Foo2", "Foo3", "Foo3", "Foo1", "Foo1" };
var grouped = list
.GroupBy(s => s)
.Select(group => new { Word = group.Key, Count = group.Count() });
var items= myList
.GroupBy(g => g)
.Select(t => new {count= t.Count(), key= t.Key });
foreach (var group in items)
Console.WriteLine ( group.key + " " + group.count);
var grouped = select new
{
Foo= grp.Key,
Bar= grp.Select(x => x.SomeField).Distinct().Count()
};
a working example with the NorthWind database so that you can check::
NWindCustomersDataContext dc = new NWindCustomersDataContext();
var query = (from c in dc.Customers
join o in dc.Orders on c.CustomerID equals o.CustomerID
group o by c.CustomerID into g
select new
{
CustomerID = g.Key,
Company = (from cust in dc.Customers
where cust.CustomerID == g.Key
select cust).ToList(),
Count = g.Select(x => x.OrderID).Distinct().Count()
}).OrderByDescending(y => y.Count);
foreach (var item in query)
{
Response.Write("CustomerID: " + item.CustomerID + "</br>" + "CompanyName: " + item.Company[0].CompanyName.ToString() + "</br>");
}
Here you can find a very good example
A good solution is available on http://msdn.microsoft.com/en-us/library/vstudio/bb534304(v=vs.100).aspx
It groups data by key; each key has it's own list of data you can iterate over it.
Related
I have following scenario where I want to find duplicates after forming the group and realign/format the duplicate data with some common class.
Example -
var lst = new List<Test>
{
new Test{Category="A",Class="Class1",Id="101",Name="John"},
new Test{Category="B",Class="Class2",Id="102",Name="Peter"},
new Test{Category="A",Class="Class2",Id="103",Name="David"},
new Test{Category="C",Class="Class3",Id="104",Name="Julia"},
new Test{Category="D",Class="Class4",Id="105",Name="Ken"},
new Test{Category="A",Class="Class1",Id="106",Name="Robert"},
};
I have created the group as -
var group =
from c in lst
group c by new
{
c.Category,
c.Class
} into g
select new
{
Category = g.Key.Category,
Class = g.Key.Class,
Id = lst.Where(x => g.Key.Category == x.Category && g.Key.Class==x.Class)
.Select(y => y.Id).ToList()
};
Which results me 2 group items for Category A with different Classes -
GroupItem1 - Category = "A" , Class = "Class1", Id = {101,106}
GroupItem2 - Category = "A" , Class = "Class2", Id = {103}
So I have requirement to show result in such case as below with other categories as -
Category = "A", Class = "Class1 OR SomeCommonClass", Id = {101,106,103}
Is it possible to achieve this result with minimum code and optimized logic.
If you want to group by Category and get the result below is the query.
var group =
from c in lst
group c by new
{
c.Category
} into g
select new
{
Category = g.Key.Category,
Class = lst.Where(x => g.Key.Category == x.Category).Select(y => y.Class).ToList(),
Id = lst.Where(x => g.Key.Category == x.Category)
.Select(y => y.Id).ToList()
};
Replace your group query with this:
var groups =
from c in lst
group c by c.Category into g
select new { Category = g.Key, Class = g.Select(c => c.Class).Distinct().Join(" or "), IDs = g.Select(c => c.Id).ToList() };
where Join is an IEnumerable extension method:
public static string Join(this IEnumerable<string> strings, string sep) => String.Join(sep, strings.ToArray());
var group = lst.GroupBy(l => l.Category)
.Select(x => new
{
Category = x.Key,
Class = string.Join(" OR ", x.Select(c => c.Class).Distinct()),
Ids = x.Select(c => c.Id).ToList()
}).ToList();
How do I do this
Select top 10 Foo from MyTable
SELECT TOP (30) Item, Descripcion, SUM(Amount) AS Suma
FROM Venat
GROUP BY Item, Descripcion
ORDER BY Suma
in Linq to SQL?
with this only agrup by Item but not Description
var filtroprimeros30 = from nuevo in registrosVipDosAños
group nuevo by nuevo.Item into g
select new
{
Item = g.Key,
Suma = g.Sum(nuevo => nuevo.Amount)
};
Use anonymous type for grouping:
var filtroprimeros30 =
(from nuevo in registrosVipDosAños
group nuevo by new { nuevo.Item, nuevo.Description } into g // here
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);
I'd actually go this way (because query syntax has nice syntax for grouping, but do not have ability to take N items):
var items = from n in registrosVipDosAños
group n by new { n.Item, n.Description } into g
select new {
g.Key.Item,
g.Key.Description,
Suma = g.Sum(x => x.Amount)
};
var topItems = items.OrderBy(x => x.Suma).Take(30);
Query still will be executed only once, but now it's more readable.
syntax alternative
var filtroprimeros30 = registrosVipDosAnos
.GroupBy(m => new {m.Item, m.Description})
.Select(g => new {
Item = g.Key.Item,
Description = g.Key.Description,
Suma = g.Sum(n => n.Amount)
})
.OrderBy(x => x.Suma)
.Take(30);
If I have the following collection:
var foos = new List<Foo>
{
new Foo{ Name = "A", Value = 1 },
new Foo{ Name = "B", Value = 1 },
new Foo{ Name = "B", Value = 2 },
new Foo{ Name = "C", Value = 1 },
};
And I want to end-up with:
A-1
B-2
C-1
Where in the case of the duplicate "B" I want to select the "B" with the highest Value?
Something like:
var filteredFoos = foos.GroupBy(x => x.Name).Select_Duplicate_With_Highest_Value
var query = from p in foos
group p by p.Name into g
select new
{
Name = g.Key,
Value = g.Max(a => a.Value)
};
var filteredFoos =
foos.GroupBy(x => x.Name)
.Select(x => new { Name = x.Key, Value = x.Max(f => f.Value) });
Try this query:
var filteredFoos = foos.GroupBy(x => x.Name)
.Select(p => new { p.Key, p.Max(x => x.Value) });
For anyone with more than 2 columns:
var subquery = from p in foos
group p by p.Name into g
select new
{
Name = g.Key,
Value = g.Max(a => a.Value)
};
var query = from f in foos
join s in subquery
on f.Name equals s.Name
where f.Value == s.Value
select f;
If this is against SQL, make sure Name is a primitive.
I have some SQL and am trying to make the equivalent in LINQ. This is the SQL:
SELECT Categories.CategoryDescription, Categories.CategoryType AS Type,
Categories.Category, COUNT(CategoryLinks.OrgID) AS CountOfOrgs
FROM CategoryLinks
INNER JOIN Categories ON Categories.CategoryID = CategoryLinks.CategoryID
GROUP BY Categories.Category, Categories.CategoryType, Categories.CategoryDescription
ORDER BY CategoryDescription ASC
Essentially, I want a list of everything from the Categories table and a count of the number of OrgId's in the CategoryLinks table that links to it.
Below is the query I am performing at the moment. There has to be a more efficient way to do this. Am I wrong?
var cnts = (from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID
group new { c, cl } by new
{
c.CategoryID
} into g
select new
{
CategoryID = g.Key.CategoryID,
categoryCount = g.Count()
});
var results = (from c in db.Categories
join cn in cnts on c.CategoryID equals cn.CategoryID
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
cn.categoryCount
});
I think you want to use the GroupJoin method:
Categories.GroupJoin(
CategoryLinks,
x => x.CategoryID,
y => y.CategoryID,
(x,y) => new{
x.CategoryID,
x.CategoryDescription,
x.CategoryType,
Category = x.Category1,
CategoryCount = y.Count() })
In query syntax, this is written as join..into:
from c in db.Categories
join cl in db.CategoryLinks on c.CategoryID equals cl.CategoryID into catGroup
select new
{
c.CategoryID,
c.CategoryDescription,
c.CategoryType,
Category = c.Category1,
CategoryCount = catGroup.Count()
}
Try this:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new {count = g.Count(), Category = g.Key});
It returns count and all data that is in Category. We group by all columns in category and place result in new anonymous type variable that contains 2 properties: Count, that contains count and Category that is of type Category and contains all data that is in category row.
If you want, you can rewrite it as:
var bbb = categories.Join(categoryLinks, c => c.CategoryID, cl => cl.CategoryId, (c, cl) => new {c, cl})
.GroupBy(g => g.c)
.Select(g => new
{
CategoryID = g.Key.CategoryId,
CategoryDescription = g.Key.CategoryDescription,
CategoryType = g.Key.CategoryType,
Category = g.Key.Category1,
categoryCount = g.Count()
});
how to do it?
I've fount this code in How to Count Duplicates in List with LINQ :
var list = new List<string> { "a", "b", "a", "c", "a", "b" };
var q = from x in list
group x by x into g
let count = g.Count()
orderby count descending
select new { Value = g.Key, Count = count };
foreach (var x in q)
{
MessageBox.Show("Value: " + x.Value + " Count: " + x.Count);
}
But how to modify it to count duplicates in datagridview? For example datagridview1[7,i] where i is number of rows in datagriview.
EDIT
Now my code is looking like that:
var list = dataGridView1.Rows.OfType<DataGridViewRow>()
.GroupBy(x => x.Cells["TestValues"].Value)
.Select(g => new { Value = g.Key, Count = g.Count(), Rows = g.ToList() })
.OrderByDescending(x => x.Count);
var q = from x in list
group x by x into g
let count = g.Count()
orderby count descending
select new { Value = g.Key, Count = count };
foreach (var x in q)
{
// dataGridView1[7, x].Value.ToString();
MessageBox.Show("Value: " + x.Value + " Count: " + x.Count +"Rows: " );
}
Something like this should work:
var list = myDataGridView.Rows.OfType<DataGridViewRow>()
.Select(x => x.Cells["MYCOLUMN"].Value.ToString());
var q = from x in list
group x by x into g
let count = g.Count()
orderby count descending
select new { Value = g.Key, Count = count };
where "MYCOLUMN" is the name of the column that you want, or, alternatively, you can pass the column index.
EDIT :
this code returns a list of items that contains also the list of rows with the duplications:
var q = myDataGridView.Rows.OfType<DataGridViewRow>()
.GroupBy(x => x.Cells["MYCOLUMN"].Value.ToString())
.Select(g => new {Value=g.Key, Count=g.Count(), Rows=g.ToList()})
.OrderByDescending(x => x.Count);
so if you have 5 rows e.g. :
ID MYCOLUMN
0 A
1 B
2 C
3 A
4 B
q will contain 3 elements:
Key="A", Count=2, Rows={ [0 - A] [3 - A]}
Key="B", Count=2, Rows={ [1 - B] [4 - B]}
Key="C", Count=1, Rows={ [2 - C] }