I have some code that groups a table by "Value1" and some loops that add the top row of each group to a list. This is a pretty ugly way to do this, and I was wondering if I could replace one of the foreach loops with a couple more lines in my LINQ query? Problem is, I don't have the foggiest idea how to do this.
var Result =
from a in DB.Table1
group new {Values = a} by a.Value1 into c
select new {everything = c};
foreach (var Row in Result)
{
foreach (var RowAll in Row.Everything)
{
List.Add(new List<string>() {RowAll.Value1, RowAll.Value2})
break;
}
}
Use Enumerable.First:
var List =
(from Row in Result
let RowAll = row.Everything.First()
select new List<string>() {RowAll.Value1, RowAll.Value2}
).ToList();
Or, combined with your original query:
var List =
(from a in DB.Table1
group a by a.Value1 into c
select new List<string>() {c.Key, c.First().Value2}
).ToList();
Use FirstOrDefault:
var query = from row in result
let rowAll = row.Everything.FirstOrDefault()
where rowAll != null
select new List<string> {rowAll.Value1, rowAll.Value2};
var list = query.ToList();
Rereading you first query I realised you are grouping on a property of 'a' so there should be no empty groupings. First() should be safe as in the other posters example.
Related
I has a table Project
id|title
___________________
1|water blue
2|test water blue low test
3|low blue
I has a list Search(Search list is dynamic and fill with user with any value and with any number row)
string[] search = new string[] { "water", "blue", "low" };
I want write this query with ef6
select * from project
where title like '%water%' and title like'%blue%' and title like '%low%'
I write this code but this return all row (i want only row 2 water blue low)
var result = (from p in context.project
where seartch.Contains(p.title)
select p
).ToList();
Please help me
Try something like this
var result = search.Where(x=>x.Contains("water") || x.Contains("blue")).ToArray();
Array.ForEach(result, Console.WriteLine);
UPDATE
var result = context.project.Where(x=>Array.IndexOf(search, x.Title) > -1);
You could try this
You will only get the row 2. As it take consideration of matching all records in your search string.
from p in context.project
.Where(g => search.All(h => g.Title.Contains(h)));
Your current query is the wrong way around. The equivalent SQL would be
WHERE title IN ('water', 'blue', 'low')
The correct query can be built by iterating over the array of search terms, and create a where term for each. The terms are implicitly AND'ed by linq:
IQueryable<Project> query = context.project;
foreach (var s in search) {
query = query.Where(x => x.Title.Contains(s));
}
var result = query.ToList();
By SQL-like query
var result = (from p in context.project
where (p.title.Contains(search[0])& p.title.Contains(search[1])&p.title.Contains(search[2])
).ToList();
By lambda exp
var result= context.project.Where(p=>p.title.Contains(search[0])&p.title.Contains(search[1])&p.title.Contains(search[2])).ToList();
You can achieve it in this way
var query = from p in context.project;
foreach(var item in search)
query.Where(p => p.Title.Contains(item));
var result = query.ToList();
I want to drill down into a particular item in my data and output the list of results to the output window. My query result looks like this
private IEnumerable<DataRow> _data;
var query = from data in this._data
group data by data.Field<string>("Form Name") into groups //same as Form ID
select new
{
formName = groups.Key,
items = from d in groups
group d by d.Field<string>("Item Name") into grps
let name = grps.Key
let documentIDGroups = grps.GroupBy(t => t.Field<string>("Document ID"))
let documentIDGroupsCount = documentIDGroups.Count()
let distinctDocumentValueCount = from data in documentIDGroups
select new
{
docID = data.Key,
distinctDocValueCount = data.Where(t => string.IsNullOrEmpty(t.Field<string>("Document Value").Trim()) == false).Select(t => t.Field<string>("Document Value")).Distinct().Count()
}
let sum = distinctDocumentValueCount.Sum(t => t.distinctDocValueCount)
let distinctItemsNames = from data in grps
select data.Field<string>("Item Name").Distinct().Count()
let count = distinctItemsNames.Count()
select new
{
itemName = name,
documentIDGroups,
documentIDGroupsCount,
averageChoices = Math.Round(((decimal)sum / documentIDGroupsCount), 2),
distinctDocumentValueCount,
sum
}
};
So on that query result I want to drill down into a particular form name, and from there get a particular Item Name and so on
so the first step is to get the grouping of items and I have
var items = from d in query where d.formName == "someName" select d.items;
but I don't know how to isolate the items by a particular string.
I want to do the following
var item = from d in items where d.itemName == "anItemName" select d;
But I don't know the syntax.
Use the .FirstOrDefault extension if you expect a single item to be returned from your query. SO:
var item = (from d in items where d.itemName == "anItemName" select d).FirstOrDefault();
I've looked at several answers to similar questions, but none of them solve my problem. All I need to do is get distinct values from a LINQ query (that queries a XML file) and put them into a list. Here is what I have tried:
var XmlData = XDocument.Load("PathToFile");
List<string> XmlItems = new List<string>();
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
XmlItems.AddRange(XQuery);
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
The Distinct() function call is not giving the expected result. I'm unfamiliar with how to get distinct values from a LINQ query. Any suggestions?
At this point, your Distinct
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
is only for (m.Attribute("TheAttribute").Value), not for the whole statement
You may need to change it to
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString()); //get everything first, ToString probably needed
var XQueryDistinct = XQuery.Distinct(); //get distinct among everything you got
You have the .ToString() and .Distinct() in the wrong places.
var XmlData = XDocument.Load("PathToFile");
List<string> XmlItems = new List<string>();
var XQuery = from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value).Distinct().ToString();
XmlItems.AddRange(XQuery);
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
becomes:
var XmlData = XDocument.Load("PathToFile");
var XmlItems = (from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString())).Distinct();
foreach (var item in XmlItems)
{
ComboBoxTeams.Items.Add(item);
}
If you have a list of simple values, you need to remove the use of Distinct in your select and put after.
var XQuery = (from m in XmlData.Root.Elements()
where m.Attribute("Category").Value.ToString().Equals("TheCategory")
select (m.Attribute("TheAttribute").Value.ToString())).Distinct();
If you have complex objects you have two alternatives:
Using morelinq you can use DistinctBy:
XmlItems.DistinctBy(x => x.WhateverProperty);
Otherwise, you can use a group:
XmlItems.GroupBy(x => x.idOrWhateverOtherProperty)
.Select(g => g.First());
You might try
var uniqueList = yourList.Distinct().ToList();
after you got your non-unique list.
I have the below code to return a list of strings.
public List<string> Top5CodesForToday()
{
var date = DateTime.Now;
var resultList = new List<string>();
using (var db = new PillowContext())
{
var qry = (from d in db.DownTimes
where DbFunctions.TruncateTime(d.DateTime) == DbFunctions.TruncateTime(date)
group d by new {d.Code}
into g
let total = g.Sum(x => x.Amount)
orderby total descending
let top5 = g.Take(5).ToList()
select new {g.Key.Code, Total = total});
foreach (var item in qry)
{
int x = item.Code;
var results = from r in db.DownTimeCodes
where r.Code == x
select r.Description;
resultList.Add(results.ToString());
}
}
return resultList;
}
When I look at the contents of returnList I am seeing the correct number of items however each item is made up of the actual query syntax, not the data itself. I have seen this before and usually solve it by doing .ToList() however I am unsure how I could change my code to solve this
The problem here is that when you are calling ToString the query is not executed yet, so essentially you are calling ToString on a IQueryable object, receiving the query instead of results. You need to call something to execute the query.
You can call ToList() still:
var results = (from r in db.DownTimeCodes
where r.Code == x
select r.Description).ToList();
resultList.AddRange(results);
Or, if you expect just one result, call FirstOrDefault()/SingleOrDefault():
var results = (from r in db.DownTimeCodes
where r.Code == x
select r.Description).FirstOrDefault();
resultList.Add(results);
You are calling ToString() on List<>. As default for most complex types, it just writes out type name not the data.
This line
resultList.Add(results.ToString());
should be changed to
resultList.AddRange(results);
I want to select elements from myCollection using myFilters for filtering:
var myFilters = new List<string> {"111", "222"};
var myCollection = new List<SomeClass> {
new SomeClass ("111"),
new SomeClass ("999")
};
from filter in myFilters
from item in myCollection
where item.Name == filter
select item
would return the "111" item.
However, if myFilters is empty I want to return all the items from myCollection.
var myFilters = new List<string> ();
var myCollection = new List<SomeClass> {
new SomeClass ("111"),
new SomeClass ("999")
};
// Here's where I'm lost...
from filter in myFilters
from item in myCollection
where item.Name == filter
select item
would return all items ("111" and "999").
If these collections are going to be sizable, then I recommend using a join. It would look something like this:
var result =
myFilters.Any() ?
from item in myCollection
join filter in myFilters
on item.Name equals filter into gj
where gj.Any()
select item
: myCollection;
Opportunities for using joins are easily overlooked. This join approach will outperform the contains approach when the lists are remotely large. If they're small and performance is acceptable, then use whichever seems the clearest.
var result = myCollection
.Where(i => (!myFilters.Any() || myFilters.Contains(i.Name)));
The best you're going to be able to do is project the filters into SomeClass. Something like:
var results = myCollection.Any() ?
myCollection.Where(item => myFilters.Contains(item.Name)) :
myFilters.Select(f => new SomeClass (f));
How about this?
var myFilters = new List<string> ();
var myCollection = new List<SomeClass> {new SomeClass ("111"), new SomeClass ("999")};
// Here's where I'm lost...
from filter in myFilters
from item in myCollection
where item.Name == filter || !myFilters.Any()
select item
Selecting from two collections performs a join based on your where clause. The join condition above says join on item.Name equal to filter OR select it if there are no filters available.
Try this:
var result = myCollection.Where(s => !myFilters.Any() ||
myFilters.Contains(s.Name));
//EDIT: commented these lines..based on comment by #Servy
//var result = myCollection.Where(s => myFilters.Count == 0 ||
// myFilters.Contains(s.Name));
Maybe it would be better to count filter collection only once:
bool isFilterEmpty = !myFilters.Any();
//bool isFilterEmpty = myFilters.Count == 0; //...or like this
var result = myCollection.Where(s => isFilterEmpty ||
myFilters.Contains(s.Name));
EDIT
I'd even say that the answer by #itsme86 is correct, but, I guess, he has confused your collections. So his answer should look somehow like this:
var results = myFilters.Any()
? myCollection.Where(item => myFilters.Contains(item.Name))
: myCollection;