I have the following class
public class Group
{
public string Id { get; set; }
public string Name { get; set; }
}
and 2 lists List<string> groupRestrict and List<Group> groups
now the group list contains some groups with all fields filled in and I want to select all the restricted groups, the groupRestrict list contains just the name of the groups.
I tried some things, but for some reasons, it always returns an empty list. this as my last test:
var lst = groups.Where(j => groupRestrict.Contains(j.Name)).ToList();
Any clue what might be going wrong?
Edit: Like the comments said, this should have worked, it was the input that had some ' but now I would like to have that the groupRestrict doesn't have to be the exact name, but can use 'like' features.
current expression:
var restrictedGroups = (from gr in groupRestrict join g in groups on gr equals g.Name select g).ToList();
Try:
var lst = groups.Where(j => groupRestrict.Any(x=> j.Name.Contains(x))).ToList();
this would match all groups with names that contain one or more strings from the searchList.
Case insensitive variant would be:
var lst = groups.Where(j => groupRestrict.Any(x=> j.Name.ToLower().Contains(x.ToLower()))).ToList();
Allthough it would be better to convert the groupRestrict to lowercase prior to the query in this case and you can omit the .ToLower() call for x:
string[] lowerCaseGroupRestrict = groupRestrict.Select(x=> x.ToLower()).ToArray();
var lst = groups.Where(j => lowerCaseGroupRestrict.Any(x=> j.Name.ToLower().Contains(x))).ToList();
Related
Codewise, what it the cleanest way to do this using linq? Below, I have a crude example where I want to find a matching class instance based on name.
class item
{
string name {get;set;}
int identifier {get;set;}
}
void DoSomething()
{
List<item> List1 = GetSampleItems();
List<item> List2 = GetOtherSampleItems();
for(int a=0;a<List1.count;a++)
{
for(int b=0;b<List2.count;b++)
{
if(List1[a].identifier == List2[b].identifier)
{
List1[a].name = List2[b].name;
}
}
}
}
Linq is for querying, not updating, so you'll still need to loop through the results to make the changes, but you can join to match up the two lists like so:
var query = from l1 in List1
join l2 in List2
on l1.identifier equals l2.identifier
select new {l1, l2};
Now loop through the query to update the l1 items:
foreach(var item in query)
item.l1.name = item.l2.name;
As a side note, there's nothing wrong with the way you're doing it (other than you could break out of the inner loop if a match is found). If you understand how it works and the performance is acceptable, there's no compelling reason to change it.
This should work:
var query = from l1 in List1
join l2 in List2 on l1.identifier equals l2.identifier
select new
{
l1values = l1,
l2Name = l2.name
};
foreach(var item in query)
item.l1Values.name = item.l2Name;
A better way is using a Dictionary<TK,TV>:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
List1.ForEach(x => {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
});
Or as #Rawling says, use a foreach loop instead:
Dictionary<int,item> l2dic = List2.ToDictionary(x => x.identifier);
item itm;
foreach(item x in List1) {
if(l2dic.TryGetValue(x.identifier,out itm)) {
x.name = itm.name;
}
}
Ideone demo (with slight modifications to your item class).
This runs on average in linear time whereas your approach runs in quadratic time.
The assumption is however that the identifiers are unique: no two elements in the same list can have the same identifier.
A concluding note is that variables in general start with a lowercase character so list1 and list2 whereas classes and properties start with a capital one (this Item, Identifier and Name).
I have a List of the following object :
public class Item
{
public DateTime DliveryDate { get; set; }
public String Order { get; set; }
}
How can i group this List<Item> by Date using LINQ?
I used the following query but didn't got excepted result in a group by dates Got a List object with a junk date of 0001/1/1
var r = from i in Items
group i by i.DliveryDate into s
select s;
This should return what you need:
var listdategroup = from x in psrAlertLogItems.AsEnumerable<Item>()
group x by x.DliveryDate.Date into s
select s;
Maybe your ChangeDateTime contains hour/time information , you should do
var listdategroup = from i in psrAlertLogItems
group i by i.DliveryDate.Date into s select s;
to get only the day component of your datetime
May be this can help u..
var sorted_lists = from sort in lists
group sort by sort.DateInfo into sorted
select sorted;
I'm getting the correct result..
have you tried it using the extension method
var itemsGruopedByDate = Items.GroupBy(item => item.DliveryDate ).ToList();
Just an alternative.
I hope its of any use.
Cheers.
I have an Entity Class called Session and it containts two attributes: LecturerOne and LectureTwo. I want to create a union of all the distinct names in LecturerOne and LecturerTwo:
I got just LecturerOne working.
public List<string> ListLecturer()
{
var lecturerNames = (from s in db.Sessions
select s.LecturerOne).Distinct();
List<string> lecturerList = lecturerNames.ToList();
return lecturerList;
}
One option:
var list = db.Sessions.SelectMany(s => new string[] { s.LecturerOne,
s.LecturerTwo })
.Distinct()
.ToList();
I don't know offhand how EF will treat that, but it's worth a try...
Alternatively, similar to Jamiec's answer but IMO simpler:
var list = db.Sessions.Select(s => s.LecturerOne)
.Union(db.Sessions.Select(s => s.LecturerTwo))
.ToList();
(Union already returns distinct results, so there's no need to do it explicitly.)
var lecturerOnes = (from s in db.Sessions
select s.LecturerOne);
var lecturerTwos = (from s in db.Sessions
select s.LecturerTwo);
List<string> lecturerList = lecturerOnes.Union(lectureTwos).ToList();
I have an array of objects. The object has two properties a value and an index.
I use a linq to entities query with the contains keyword to bring back all results in a table that match up to value.
Now here is the issue... I want to match up the results to the object index...
what is the fastest best way to perform this. I can add properties to the object.
It is almost like I want the query results to return this:
index = 1;
value = "searchkey"
queryvalue = "query value"
From your question I think I can assume that you have the following variables defined:
Lookup[] (You look-up array)
IEnumerable<Record> (The results returned by your query)
... and the types look roughly like this:
public class Lookup
{
public int Index { get; set; }
public int Value { get; set; }
}
public class Record
{
public int Value { get; set; }
/* plus other fields */
}
Then you can solve your problem in a couple of ways.
First using an anonymous type:
var matches
= from r in records
join l in lookups on r.Value equals l.Value
group r by l.Index into grs
select new
{
Index = grs.Key,
Records = grs.ToArray(),
};
The other two just use standard LINQ GroupBy & ToLookup:
IEnumerable<IGrouping<int, Record>> matches2
= from r in records
join l in lookups on r.Value equals l.Value
group r by l.Index;
ILookup<int, Record[]> matches3
= matches2.ToLookup(m => m.Key, m => m.ToArray());
Do these solve your problem?
Just a shot in the dark as to what you need, but the LINQ extension methods can handle the index as a second paramter to the lambda functions. IE:
someCollection.Select( (x,i) => new { SomeProperty = x.Property, Index = i } );
I have a string with semi-comma separated names:
string names = "Jane;Harry";
I also have a list of customer objects:
public class Customer
{
public string FirstName { get; set; }
public string LastName { get; set; }
}
List<Customer> customers = new List<Customer>();
customers.Add(new Customer(){FirstName="John", LastName="Doe"});
customers.Add(new Customer(){FirstName="Jane", LastName="Doe"});
customers.Add(new Customer(){FirstName="Harry", LastName="Potter"});
var query = from c in customers
select c;
How do I create a query that returns only those customers that has a first name that is in the semi-comma separated list?
Something like the T-SQL SELECT FistName FROM customer WHERE FirstName IN (list)
(sort of)
Well, you should really split the string up to start with - otherwise you'll get a match for "Jane" even if the list is "Janet;Harry".
You could do:
string[] validNames = names.Split(';');
var query = customers.Where(c => validNames.Contains(c.FirstName));
Another option is to use a HashSet, which will perform a lot better when the list is very large:
HashSet<string> validNames = new HashSet<string>(names.Split(';'));
var query = customers.Where(c => validNames.Contains(c.FirstName));
I've used dot notation here instead of a query expression because it's simpler when you're just applying a clause or two. As a query expression though, it would be:
var query = from c in customers
where validNames.Contains(c.FirstName)
select c;
You can try this.
List firstnames = names.Split(';').ToList();
var query = from c in customers
where firstnames.Contains(c.FirstName)
select c ;
It Will Helps
string allid = "11,12,13,14,15,16";
string[] arrid = allid.Split(',');
var data = context.MyModels.Where(x => arrid.Contains(x.ProjectId.ToString()));