I cant find a way how to do a multiple filtering with LINQ.
what i want to do:
1.Filter the Version(Achieved)
2.Filter down the CompanyName(filtering/removing duplicates)
3.Get the Latest Timestamp
4.Then add all to a List.
Here is so far the code that i have written(which is not working).
public List<ReleaseStatistics> GetReleaseStatistics(IQueryable<InstallationInformation> input, IQueryable<DBContext.Version> mapping)
{
List<ReleaseStatistics> Releasestats = new List<ReleaseStatistics>();
foreach (var version in mapping)
{
IQueryable<InstallationInformation> QueryResult1 = input.Where(x => x.ProductVersion == version.VersionNumber);
IQueryable<InstallationInformation> QueryResult2 = QueryResult1.GroupBy(x => x.CompanyName).SelectMany(y => y);
List<InstallationInformation> ListofInstallationInformation = QueryResult2.ToList<InstallationInformation>();
if (ListofInstallationInformation.Count >= 1)
{
Releasestats.Add(new ReleaseStatistics
{
ReleaseVersion = version.ReleaseName,
CustomerCount = QueryResult1.Where(x => x.ProductVersion == version.VersionNumber).Count()
});
}
}
return Releasestats;
}
Addition information:
One of the problem is that there are duplicate and i want to Filter/remove them, but i want to get the latest timestamp of each CompanyName and then add it to the list.
the problem is that the line
IQueryable<InstallationInformation> QueryResult2 = QueryResult1.GroupBy(x => x.CompanyName).SelectMany(y => y);
actually does nothing.
Suppose QueryResult1 is
CompanyName | F1 | F2 |
CN1 | f1a | f2a |
CN1 | f1a | f2a |
CN2 | f1b | f2b |
then QueryResult1.GroupBy(x => x.CompanyName) is
Group | Data
CN1 | CompanyName | F1 | F2 |
CN1 | f1a | f2a |
CN1 | f1a | f2a |
CN2 | CompanyName | F1 | F2 |
CN2 | f1b | f2b |
then QueryResult1.GroupBy(x => x.CompanyName).SelectMany(y => y); is again
CompanyName | F1 | F2 |
CN1 | f1a | f2a |
CN1 | f1a | f2a |
CN2 | f1b | f2b |
what you want to do is probably
var QueryResult2 = QueryResult1.GroupBy(x => x.CompanyName).Select(y => new {CompanyName = y.Key, MaxTimestamp = y.Max(z => z.TimeStamp)});
I did it with classes to simulate your query
DBContext context = new DBContext();
List<InstallationInformation> input = new List<InstallationInformation>();
var query = (from m in context.mapping
join i in input on m.VersionNumber equals i.ProductVersion
select new { version = m.VersionNumber, companyName = i.CompanyName}
).ToList();
List<ReleaseStatistics> results = query.GroupBy(x => x.version).Select(x => new ReleaseStatistics() { ReleaseVersion = x.Key, CustomerCount = x.Distinct().Count() }).ToList();
}
}
public class DBContext
{
public List<Version> mapping { get; set; }
}
public class InstallationInformation
{
public int ProductVersion { get; set; }
public string CompanyName { get; set; }
}
public class Version
{
public int VersionNumber { get; set; }
}
public class ReleaseStatistics
{
public int ReleaseVersion { get; set; }
public int CustomerCount { get; set; }
}
HERE WAS MY END RESULT:
public List<ReleaseStatistics> GetReleaseStatistics(IQueryable<InstallationInformation> input, IQueryable<DBContext.Version> mapping)
{
List<ReleaseStatistics> Releasestats = new List<ReleaseStatistics>();
foreach (var version in mapping)
{
IQueryable<InstallationInformation> QueryResult1 = input.Where(x => x.ProductVersion == version.VersionNumber);
IQueryable<string> companynamecollection = QueryResult1.Select(x => x.CompanyName).Distinct();
List<InstallationInformation> listofAggregatedInstallationInformation = new List<InstallationInformation>();
foreach (var item in companynamecollection)
{
var maxdatetime = QueryResult1.Where(x => x.CompanyName == item).Select(x => x.Timestamp).Max();
IQueryable<InstallationInformation> listofresult = QueryResult1.Where(y => y.CompanyName == item && y.Timestamp == maxdatetime);
foreach (var item2 in listofresult)
{
listofAggregatedInstallationInformation.Add(new InstallationInformation
{
InstallationInformationID = item2.InstallationInformationID,
LicenceKey = item2.LicenceKey,
ProductName = item2.ProductName,
ProductVersion = item2.ProductVersion,
CompanyName = item2.CompanyName,
Timestamp = item2.Timestamp,
ImportRunID = item2.ImportRunID
});
}
}
if (listofAggregatedInstallationInformation.Count >= 1)
{
Releasestats.Add(new ReleaseStatistics
{
ReleaseVersion = version.ReleaseName,
CustomerCount = listofAggregatedInstallationInformation.Where(x => x.ProductVersion == version.VersionNumber).Count()
});
}
}
return Releasestats;
}
Related
I currently have the following classes:
public class NavigationItem
{
public int ID { get; set; }
public string Title { get; set; }
public int ParentID { get; set; }
public List<NavigationItem> Children { get; set; }
}
public class FlatItem
{
public int ID { get; set; }
public string Title { get; set; }
public int ParentID { get; set; }
}
I have a sample data as follows:
+====+============+==========+
| ID | Title | ParentID |
+====+============+==========+
| 1 | Google | |
+----+------------+----------+
| 2 | Microsoft | |
+----+------------+----------+
| 3 | Oracle | |
+----+------------+----------+
| 4 | Gmail | 1 |
+----+------------+----------+
| 5 | Sheets | 1 |
+----+------------+----------+
| 6 | Adsense | 1 |
+----+------------+----------+
| 7 | Azure | 2 |
+----+------------+----------+
| 8 | SharePoint | 2 |
+----+------------+----------+
| 9 | Office | 2 |
+----+------------+----------+
| 10 | Java | 3 |
+----+------------+----------+
| 11 | Word | 9 |
+----+------------+----------+
| 12 | Excel | 9 |
+----+------------+----------+
| 13 | PowerPoint | 9 |
+----+------------+----------+
I already have the code to pull all the information from the sample data above and turn it into a List<FlatItem> object.
What's the best approach so that I can have a List<NavigationItem> object which will look like something below:
Google
Gmail
Sheets
AdSense
Microsoft
Azure
SharePoint
Office
Word
Excel
PowerPoint
Oracle
Java
I'm thinking of creating a recursive method to loop through my List<FlatItem> then structure it in a way to be a nested list of NavigationItem.
No need for recursion. You could use LINQ to build the structure easily:
List<FlatItem> flatItems = ...;
var navigationItems = flatItems.Select(
i => new NavigationItem { ID = i.ID, Title = i.Title, ParentID = i.ParentID }
).ToList();
foreach (var i in navigationItems)
i.Children = navigationItems.Where(n => n.ParentID == i.ID).ToList();
// get Google, Microsoft, Oracle items
var rootNavigationItems = navigationItems.Where(n => n.ParentID == 0);
Try this:
List<FlatItem> source = new List<UserQuery.FlatItem>()
{
new FlatItem() { ID = 1, Title = "Google", ParentID = null },
new FlatItem() { ID = 2, Title = "Microsoft", ParentID = null },
new FlatItem() { ID = 3, Title = "Oracle", ParentID = null },
new FlatItem() { ID = 4, Title = "Gmail", ParentID = 1 },
new FlatItem() { ID = 5, Title = "Sheets", ParentID = 1 },
new FlatItem() { ID = 6, Title = "Adsense", ParentID = 1 },
new FlatItem() { ID = 7, Title = "Azure", ParentID = 2 },
new FlatItem() { ID = 8, Title = "SharePoint", ParentID = 2 },
new FlatItem() { ID = 9, Title = "Office", ParentID = 2 },
new FlatItem() { ID = 10, Title = "Java", ParentID = 3 },
new FlatItem() { ID = 11, Title = "Word", ParentID = 9 },
new FlatItem() { ID = 12, Title = "Excel", ParentID = 9 },
new FlatItem() { ID = 13, Title = "PowerPoint", ParentID = 9 },
};
var lookup = source.ToLookup(x => x.ParentID);
Func<int?, List<NavigationItem>> build = null;
build = pid =>
lookup[pid]
.Select(x => new NavigationItem()
{
ID = x.ID,
Title = x.Title,
ParentID = x.ParentID,
Children = build(x.ID)
})
.ToList();
To start the process call build(null). That gives me this:
This does assume that the ParentId property is a int? - which your data table does suggest.
If you are ok with using recursion, you can create a function like this:
public List<NavigationItem> ChildrenOf(List<FlatItem> flatItems, int parentId)
{
var childrenFlatItems = flatItems.Where(i => i.ParentID == parentId);
return childrenFlatItems.Select(i => new NavigationItem {
ID = i.ID,
Title = i.Title,
ParentID = i.ParentID,
Children = ChildrenOf(flatItems, i.ID)})
.ToList();
}
Then, assuming that your root items have a parent id of 0 (since you aren't using nullable types), you generate the full list with:
ChildrenOf(flatsItems, 0)
Untested, however you could try this, should be fairly fast as well
var list = new List<FlatItem>();
var result = new List<NavigationItem>();
// just a helper to remember ids
var dict = new Dictionary<int, NavigationItem>();
foreach (var item in list)
{
var nav = new NavigationItem()
{
ID = item.ID,
ParentID = item.ParentID,
Title = item.Title,
Children = new List<NavigationItem>()
};
if (!dict.ContainsKey(nav.ParentID))
result.Add(nav);
else
dict[nav.ParentID].Children.Add(nav);
dict.Add(item.ID, nav);
}
no recursive, just GroupBy.
List<NavigationItem> list = ... // map from List<FlatItem>
// and init Children = new List<NavigationItem>();
var groups = list.GroupBy(x => x.ParentID).ToList();
foreach (var g in groups)
{
var items = list.Find(x => x.ID == g.Key);
if (items != null)
items.Children = g.ToList();
}
// tops is [Google, Microsoft, Oracle]
var tops = list.Where(x => x.ParentID == null).ToList();
I have a problem with getting grouped columns in LINQ.
My class:
public class DTO_CAORAS
{
public int? iORAS_KEY_CON { get; set; }
public int? iMERC_KEY {get;set;}
public double? decD_ORAS_QUA {get;set;}
}
LINQ query:
var results =
from oras in listCAORAS_Delivered
group oras by new
{
oras.iORAS_KEY_CON,
oras.iMERC_KEY
}
into orasGroup
select new
{
decD_ORAS_QUA = orasGroup.Sum(x => x.decD_ORAS_QUA)
};
List results is filled only with one column - decD_ORAS_QUA. I don't know how to get columns, by which query is grouped - IORAS_KEY_CON and iMERC_KEY? I would like to fill results with iORAS_KEY_CON, iMERC_KEY and decD_ORAS_QUA.
Input data:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 1 |
| 1 | 888 | 2 |
| 1 | 888 | 4 |
+---------------+-----------+---------------+
Desired output:
+---------------+-----------+---------------+
| iORAC_KEY_CON | iMERC_Key | decD_ORAS_QUA |
+---------------+-----------+---------------+
| 1 | 888 | 7 |
+---------------+-----------+---------------+
To also show the keys:
var results = from oras in listCAORAS_Delivered
group oras by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum(x => x.decD_ORAS_QUA)
};
As you are only grouping one column you can also:
var results = from oras in listCAORAS_Delivered
group oras.decD_ORAS_QUA by new { oras.iORAS_KEY_CON, oras.iMERC_KEY } into g
select new DTO_CAORAS {
iORAS_KEY_CON = g.Key.iORAS_KEY_CON,
iMERC_KEY = g.Key.iMERC_KEY,
decD_ORAS_QUA = g.Sum()
};
This question already has an answer here:
Take(limit) list inside Groupby in Entity Framework
(1 answer)
Closed 5 years ago.
I need to take (for example, 2), 2 messages from a conversation
example:
id = idConversation
Id | messageId | Message
---|-----------|--------
1 | 1 | "asd"
1 | 2 | "asd2"
1 | 3 | "asd3"
1 | 4 | "asd4"
2 | 5 | "asd5"
3 | 6 | "asd6"
3 | 7 | "asd7"
3 | 8 | "asd8"
3 | 9 | "asd9"
3 | 10 | "asd10"
4 | 11 | "asd11"
4 | 12 | "asd12"
4 | 13 | "asd13"
and i want that
Id messageId Message
---|-----------|--------
1 | 1 | "asd"
1 | 2 | "asd2"
2 | 5 | "asd5"
3 | 6 | "asd6"
3 | 7 | "asd7"
4 | 11 | "asd11"
4 | 12 | "asd12"
i can grouby idConversation, but i cant limit quantity using grouby in a conversation.
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Select(mensagem => new
{
// do stuff
})
}).ToList();
this is ok... but dont limit my list, when i do group.take(2).Select.....
give me "Subquery returns more than 1 row"
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Take(2).Select(mensagem => new
{
// do stuff
})
}).ToList();
error : Subquery returns more than 1 row
var test = unitOfWork.ChatMensagemRepository.GetAll()
.Where(x => x.PessoaCodigoPessoa == codigoRemetente)
.GroupBy(x => x.ChatConversaCodigoChatConversa)
.Select(group => new
{
codigoChat = group.Key,
list = group.Select(mensagem => new
{
// do stuff
}).take(2)
}).ToList();
error : Subquery returns more than 1 row
Here's an example of what I think you're after. This query will return the top 3 sudtents by GPA in each class:
using System;
using System.Collections.Generic;
using System.Data.Entity;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Ef6Test
{
class Student
{
public int Id { get; set; }
public string Name { get; set; }
public string Class{ get; set; }
public decimal GPA { get; set; }
}
class Db : DbContext
{
public DbSet<Student> Students { get; set; }
}
class Program
{
static void Main(string[] args)
{
using (var db = new Db())
{
var q = db.Students
.GroupBy(s => s.Class)
.SelectMany(g => g.OrderByDescending(s => s.GPA).Take(3));
Console.WriteLine(q.ToString());
Console.ReadKey();
}
}
}
}
I tried this code and is working fine:
class Conversation
{
public int Id;
public string Message;
public int MessageId;
}
class Program
{
static void Main(string[] args)
{
var inputList = new List<Conversation>
{
new Conversation() {Id = 1, Message = "asd0", MessageId = 1},
new Conversation() {Id = 1, Message = "asd1", MessageId = 2},
new Conversation() {Id = 1, Message = "asd2", MessageId = 3},
new Conversation() {Id = 2, Message = "asd3", MessageId = 4},
new Conversation() {Id = 2, Message = "asd4", MessageId = 5},
new Conversation() {Id = 2, Message = "asd5", MessageId = 6},
new Conversation() {Id = 3, Message = "asd6", MessageId = 7}
};
var outputList = inputList.GroupBy(x => x.Id)
.SelectMany(x => x.OrderBy(y => y.MessageId).Take(2).ToList())
.ToList();
Console.ReadKey();
}
}
I have three tables Keyword, Product and KeywordProduct.
If I try to filter "the", return A and B products
If I try to filter "matrix", return only B product
but when I filter "the matrix", I get B and A too. I need to get only B record.
that is the code:
var keywordTermList = ("the matrix").Split(' ');
db.Products
.Where(product => product.ProductKeywords.All(k => keywordTermList.Contains(k.Keyword.Name)))
Keyword Table
+-----------+---------+
| KeywordId | Name |
+-----------+---------+
| 1 | awakens |
| 2 | force |
| 3 | the |
| 4 | matrix |
+-----------+---------+
ProductKeyword Table
+------------+-----------+
| KeywordId | ProductId |
+------------+-----------+
| 3(the) | A |
| 2(force) | A |
| 1(awakens) | A |
| 3(the) | B |
| 4(matrix) | B |
+------------+-----------+
Product Table has A and B records.
How would I go about this? How can I get only B when I filter "the matrix".
If you want the subset to fully match the surperset
var query = products.Where(p => !keywordListTerm.Except(p.ProductKeywords.Select(pk => pk.Name)).Any());
Here is full example
public class Program
{
public static void Main(string[] args)
{
Product A = new Product();
A.Name = "A";
A.ProductKeywords = new List<Keyword>() {
new Keyword(){Name = "the"},
new Keyword(){Name = "force"},
new Keyword(){Name = "awakens"}
};
Product B = new Product();
B.Name = "B";
B.ProductKeywords = new List<Keyword>() {
new Keyword(){Name = "the"},
new Keyword(){Name = "matrix"}
};
List<Product> products = new List<Product>() { A, B };
var keywordListTerm = ("the force matrix").Split(' ');
var query = products.Where(p => !keywordListTerm.Except(p.ProductKeywords.Select(pk => pk.Name)).Any());
foreach (var item in query) {
Console.WriteLine(item.Name);
}
Console.ReadKey();
}
}
public class Product {
public string Name = string.Empty;
public List<Keyword> ProductKeywords;
}
public class Keyword
{
public string Name;
}
Hope this helps.
My problem is how can i join the selected rows with identical ID but different contacts
This is the output of what I'm doing
| Name | Address | Cellphone | Email |
| John | NY | n/a | johndoe#y.c |
| John | NY | 123456781 | n/a |
and i want my output to be one liner combined
| Name | Address | Cellphone | Email |
| John | NY | 123456781 | johndoe#y.c |
this is my Linq
var an = (from a in db.Info
join b in db.Contact
on a.ID equals b.InfoID
where b.ContactTypeID == 56
|| b.ContactTypeID == 59
select new
{
a.ID,
a.LastName,
a.FirstName,
a.MiddleName,
b.ContactTypeID,
b.Values
}).ToList();
List<Info> wlist = new List<Info>();
foreach (var row in an)
{
Info ci = new Info
{
ID = row.ID,
Name = row.FirstName + " " + row.MiddleName + " " + row.LastName,
ContactType = GetLookupDisplayValById(row.ContactTypeID),
ContactValue = row.Values
};
wlist.Add(ci);
}
return Json(wlist.ToList(), JsonRequestBehavior.AllowGet);
}
I hope someone can help me with this
Thanks :)
You can do it:
from info in db.Info
join contact in db.Contact
on info.ID == contact.InfoID
select new Contact(info, contact)
And your constructor will merge.
public class Contact
{
public int ID { get; set; }
public string LastName { get; set; }
public string MiddleName { get; set; }
public int ContactTypeID { get; set; }
public Contact(Info info, Contact contact)
{
ID = info.ID;
LastName = string.IsNullOrEmpty(info.LastName) ? contact.LastName : info.LastName;
}
}
try with GroupBy
var resuts = db.Info.GroupBy(i=>i.ID)
.Select(g=>new Info{
ID = g.Key,
Address = g.Fist().Address,
Cellphone = g.FistOrDefault(x=> x.Cellphone !="n/a"),
Email = g.FistOrDefault(x=> x.Email !="n/a")
}).ToList();