I need to find the 1st matching record between 2 generic Lists.
Below is the code I have written. But, even after a match is obtained, it is still processing further records. Is there any way to break from the below query? Something like "break" or "Exit for"
foreach (var itemOld in oldList)
{
var result = (from itemNew in newList
where itemNew.Id == itemOld.Id
select itemNew).ToList();
// Do processing
}
The keyword you are looking for is break;
foreach (var itemOld in oldList)
{
var result = (from itemNew in newList
where itemNew.Id == itemOld.Id
select itemNew).ToList();
if(someThingisTrue){
break;
}
}
You can do this. Both the inner and outer query will terminate as soon as a matching item is found:
foreach (var itemOld in oldList)
{
var result = (from itemNew in newList
where itemNew.Id == itemOld.Id
select itemNew).FirstOrDefault();
if (result != null)
{
// process result
break;
}
}
You can also combine them like this:
var result = (from itemNew in newList
from itemOld in oldList
where itemNew.Id == itemOld.Id
select itemNew).FirstOrDefault();
if (result != null)
{
// process result
}
The difference is that the first approach will go through newList repeatedly until a match is found. The second will go through oldList repeatedly until a match is found.
To address your comment below, if you want to process all the matches, just remove the break from the first example, or do this for the second version:
var results = from itemNew in newList
from itemOld in oldList
where itemNew.Id == itemOld.Id
select itemNew;
foreach (var item in results)
{
// process item
}
Just for fun.
var predicate = itemNew => oldList.FirstOrDefault(itemOld => itemOld.Id == itemNew.Id);
var result = newList.FirstOrDefault(predicate);
EDIT: as pointed out in the comments, I did stuff in the wrong order =(. Fixed for correctness.
A little bit late, but you can do it with a join:
using System;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public class Item
{
public int Id { get; set; }
}
public static void Main()
{
var oldList = new List<Item>();
oldList.Add(new Item() { Id = 3 });
oldList.Add(new Item() { Id = 4 });
oldList.Add(new Item() { Id = 5 });
var newList = new List<Item>();
newList.Add(new Item() { Id = 1 });
newList.Add(new Item() { Id = 2 });
newList.Add(new Item() { Id = 3 });
// here is the linq join
var result =
newList.Join(
oldList,
item => item.Id,
item => item.Id,
(itemNew, itemOld) => itemNew).FirstOrDefault();
// outputs 3
Console.WriteLine(result.Id);
}
}
Related
Problem
I need to create a List<int> basead on two properties from another list.
Example
I have a class that has two fields that I need.
public class MyClass
{
//Other fields
int? ValueId
int? ValueTwoId
}
Above code it's an example, so do not focus there.
I want to retrieve those properties like:
myClassList.ElementAt(0).ValueId = 1;
myClassList.ElementAt(0).ValueTwoId = 2;
myClassList.ElementAt(1).ValueId = 3;
myClassList.ElementAt(1).ValueTwoId = 4;
List<int> resultList = myClassList.Where(x => x.ValueId != null && x.ValueTwoId != null).Select(x => ??).ToList());
Desired Output
resultList.ElementAt(0) == 1
resultList.ElementAt(1) == 2
resultList.ElementAt(2) == 3
resultList.ElementAt(3) == 4
There's a way to achieve this using .Select(x => Something ).ToList(), without using a code like:
List<int> resultList = new List<int>();
foreach(var item in myClassList)
{
resultList.Add(item.ValueId);
resultList.Add(item.ValueTwoId);
}
Thanks in advance, sorry my poor english.
Try
List<int> resultList = myClassList
.Where(x => x.ValueId != null && x.ValueTwoId != null)
.SelectMany(x => new List<int>{x.ValueId.Value, x.ValueTwoId.Value})
.ToList();
As in:
using System;
using System.Collections.Generic;
using System.Linq;
namespace Example
{
internal class Program
{
public static void Main(string[] args)
{
var myClassList = new List<MyClass> {new MyClass(), new MyClass()};
myClassList.ElementAt(0).ValueId = 1;
myClassList.ElementAt(0).ValueTwoId = 2;
myClassList.ElementAt(1).ValueId = 3;
myClassList.ElementAt(1).ValueTwoId = 4;
var resultList = myClassList
.Where(x => x.ValueId != null && x.ValueTwoId != null)
.SelectMany(x => new List<int> { x.ValueId.Value, x.ValueTwoId.Value})
.ToList();
foreach (var i in resultList)
{
Console.WriteLine(i);
}
//Prints out:
//1
//2
//3
//4
Console.ReadLine();
}
public class MyClass
{
public int? ValueId;
public int? ValueTwoId;
}
}
}
var result = from x in myClassList
from sub in new[] { x.ValueId, x.ValueTwoId }
where sub.HasValue
select sub.Value;
It is not quite clear to me if you want to discard x.ValueIdTwoId just because x.valueId is null. If that is the case, use
var result = from x in myClassList
from sub in new[] { x.ValueId, x.ValueTwoId }
where x.ValueId.HasValue && x.ValueTwoId.HasValue
select sub.Value;
instead.
As others have noted, what you need is LINQ's SelectMany operation. The from in the code samples above translate to SelectMany, as described in the remarks for the Enumerable.SelectMany Method on MSDN.
private static List<Patient> GetPatientData()
{
return new List<Patient>()
{
new Patient(1,new List<Case>() { new Case(10, CaseType.ambulant)}),
new Patient(2,new List<Case>() { new Case(20, CaseType.ambulant), new Case(21, CaseType.ambulant), new Case(22, CaseType.stationaer),new Case(23, CaseType.teilstat) }),
new Patient(3,new List<Case>() { new Case(30, CaseType.ambulant), new Case(31, CaseType.ambulant), new Case(32, CaseType.stationaer), new Case(33, CaseType.stationaer), new Case(34, CaseType.teilstat) }),
new Patient(4,new List<Case>() { new Case(40, CaseType.ambulant), new Case(41, CaseType.stationaer), new Case(43, CaseType.teilstat), new Case(44, CaseType.ambulant), new Case(45, CaseType.stationaer), new Case(46, CaseType.teilstat) }),
new Patient(5,new List<Case>() {new Case(53, CaseType.teilstat),new Case(54, CaseType.teilstat) })
};
}
List<Patient> patientList = GetPatientData();
var result = patientList.SelectMany(item => item.CaseList.Select(itemCase=> itemCase.CaseType).Distinct());
foreach (CaseType item in result)
{
Console.WriteLine("CaseTypes = {0}",item);
}
The above code gives the list of Patient, from that I want a distinct case list. So is there any optimized way to do this from what I have done?
Dictionary<int, int> result = patientList.ToDictionary(item => item.PatientID , item=> item.CaseList.Select(x=>x.CaseType).Distinct().Count());
foreach (KeyValuePair<int,int> item in result)
{
Console.WriteLine("{0} {1}", item.Key,item.Value);
}
In Second case i am trying to get patientID & Distinct CaseType Count for that particular patient. can i optimize this one.
To get the distinct case types of all patients in that list, I used
var result =
(
from patient in patientList
from typ in patient.CaseList
select typ.CaseType
).Distinct();
foreach (var item in result)
{
Console.WriteLine("CaseTypes = {0}", item);
}
Of course, you could rewrite it method-style.
To get the same distinct case list, but per patient, try this:
var result =
(
from patient in patientList
group patient by patient.PatientID into g
from patient in g
from typ in patient.CaseList
select new { ID = g.Key, Type = typ.CaseType }
).Distinct();
foreach (var item in result)
{
Console.WriteLine("Patient {0} has the following case: {1}", item.ID, item.Type);
}
An alternative (less repeating) way to present the results is to group:
var result =
(
from patient in patientList
group patient by patient.PatientID into g
from p in g
select new { g.Key, List = p.CaseList.Select(c => c.CaseType).Distinct() }
).ToDictionary(kv => kv.Key, kv => kv.List);
foreach (var item in result)
{
Console.WriteLine("Patient {0} has the following cases:", item.Key);
foreach (var type in item.Value)
{
Console.WriteLine("\t{0}", type);
}
}
You are missing a last Distinct:
var result = patientList.SelectMany(item => item.CaseList.Select(itemCase => itemCase.CaseType).Distinct()).Distinct();
There's nothing to improve there.
You could choose to keep only the last Distinct (so there's one less Enumerator to be created) but having it gives you less results yielded out to your final Distinct. Performance then would change depending on the amount of data (number of Patients and Cases per Patient) though nothing that would make any difference.
if i don't want to specified field one by one but i want to select all field without specified. how am i going to do it?
List<test> xxx = new List<test>();
var rows = xxx.Where(s => s.test1 == "")
.GroupBy(s => s.test1)
.Select(s => new
{
test1 = s.First().test1,
test2 = s.First().test2
})
.ToList();
i dont want to use var rows = from s in xxx bla bla lba select s. but using above method. how to i do it?
Regards,
MH
It seems that you don't really want a GroupBy() at all, and what you really want is this:
List<test> xxx = new List<test>();
var row = xxx.First(s => s.test1 == "");
List<test> xxx = new List<test>();
var rows = xxx.Where(s => s.test1 == "")
.GroupBy(s => s.test1).ToList();
not really sure what u want to achieve. but do you mean like this?
Select items by group
IEnumerable<DataRow> sequence = DataTbl.AsEnumerable();
var GroupedData = from d in sequence group d by d["panelName"]; // GroupedData is now of type IEnumerable<IGrouping<int, Document>>
foreach (var GroupList in GroupedData) // GroupList = "document group", of type IGrouping<int, Document>
{
string GroupName = "";
foreach (var Item in GroupList)
{
GroupName = Item["panelName"].ToString();
string ItemReference = Item["reference"].ToString();
}
}
Consider three different lists of strings, one of which is a list of lists. I need to search them all to find a particular one.
In this sample, the result is achieved, but I would like to do it in one Linq statement. Note that I do not want to change the existing collections, nor create any new ones.
var collectionA = new List<string>() {"Item1", "Item2"};
var collectionB = new List<string>() { "Item3", "Item4" };
var listOfLists = new List<List<string>>() {new List<string>() {"Item5", "Item6"}, new List<string>(){ "Item7", "Item8"}};
//Is there a better Linq way to do this?
var searchString = "Item5";
var item = collectionA.FirstOrDefault(i => i == searchString);
if (item == null)
{
item = collectionB.FirstOrDefault(i => i == searchString);
if (item == null)
{
foreach (var listOfList in listOfLists)
{
item = listOfList.FirstOrDefault(i => i == searchString);
if (item != null)
{
break;
}
}
}
}
bool result = listOfLists.SelectMany(x => x)
.Concat(collectionA)
.Concat(collectionB)
.Any(x => x == "Item5");
var result = collectionA
.Concat(collectionB)
.Concat(listOfLists.SelectMany(i => i))
.FirstOrDefault(i => i == searchString);
You can use SelectMany to flatten list of list, add collectionA and collectionA to listOfLists first:
listOfLists.AddRange(new[] {collectionA, collectionB});
if (listOfLists.SelectMany(x => x).Any(y => y == "Item5"))
{
}
With you new edit which does not prefer to change the existing collections, nor create the new one, you can do:
if (listOfLists.Any(x => x.Any(y => y == "Item5"))
|| collectionA.Any(x => x == "Item5")
|| collectionB.Any(x => x == "Item5"))
{
}
Maybe this can help:
var collectionA = new List<string>() { "Item1", "Item2" };
var collectionB = new List<string>() { "Item3", "Item4" };
var listOfLists = new List<List<string>>() { new List<string>() { "Item5", "Item6" }, new List<string>() { "Item7", "Item8" } };
var val = from y in (from x in listOfLists[0] select x) where y == "Item5" select y;
you can modify more to get your expected result
I am unable to solve this problem with the LINQ Query.
So we have the table structure as follows:
Id || bug_category || bug_name || bug_details || bug_priority
I want to group by bug_category first. For each bug_category, I want to in turn group by bug__priority.
So basically I want something like :
bug_category = AUDIO :: No of BUGS --> Critical = 3, Medium = 2 and Low = 7 bugs.
bug_category = VIDEO :: No of BUGS --> Critical = 5, Medium = 1 and Low = 9 bugs.
The below query returns all unique combinations of category AND customer_priority:
(where RawDataList is simply a List of data which has the above mentioned structure )
var ProceesedData = from d in RawDataList
group d by new { d.bug_category, d.bug_priority } into g
select new
{
g.Key.bug_category,
g.Key.bug_priority
};
The below query returns the category followed by a list of records in that category:
var ProceesedData = from d in RawDataList
group d by d.bug_category into g
select new { g.Key, records = g
};
But I am unable to proceed further as ProcessedData(the return variable) is an unknown type. Any thoughts on this?
This is an easier way to accomplish nested groupings. I've tested it for in memory collections, whether or not your particular DB provider will handle it well might vary, or whether it performs well is unknown.
Assuming you had two properties, and wanted to group by both State and Country:
var grouped = People
.GroupBy(l => new { l.State, l.Country})//group by two things
.GroupBy(l=> l.Key.Country)//this will become the outer grouping
foreach(var country in grouped)
{
foreach(var state in country)
{
foreach(var personInState in state)
{
string description = $"Name: {personInState.Name}, State: {state.StateCode}, Country: {country.CountryCode}";
...
}
}
}
I suspect you want (names changed to be more idiomatic):
var query = from bug in RawListData
group bug by new { bug.Category, bug.Priority } into grouped
select new {
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
};
Then:
foreach (var result in query)
{
Console.WriteLine("{0} - {1} - {2}",
result.Category, result.Priority, result.Count);
}
Alternatively (but see later):
var query = from bug in RawListData
group bug by new bug.Category into grouped
select new {
Category = grouped.Category,
Counts = from bug in grouped
group bug by grouped.Priority into g2
select new { Priority = g2.Key, Count = g2.Count() }
};
foreach (var result in query)
{
Console.WriteLine("{0}: ", result.Category);
foreach (var subresult in result.Counts)
{
Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count);
}
}
EDIT: As noted in comments, this will result in multiple SQL queries. To obtain a similar result structure but more efficiently you could use:
var dbQuery = from bug in RawListData
group bug by new { bug.Category, bug.Priority } into grouped
select new {
Category = grouped.Key.Category,
Priority = grouped.Key.Priority,
Count = grouped.Count()
};
var query = dbQuery.ToLookup(result => result.Category,
result => new { result.Priority, result.Count };
foreach (var result in query)
{
Console.WriteLine("{0}: ", result.Key);
foreach (var subresult in result)
{
Console.WriteLine(" {0}: {1}", subresult.Priority, subresult.Count);
}
}
I think you're searching something like that:
var processedData =
rawData.GroupBy(bugs => bugs.bug_category,
(category, elements) =>
new
{
Category = category,
Bugs = elements.GroupBy(bugs => bugs.bug_priority,
(priority, realbugs) =>
new
{
Priority = priority,
Count = realbugs.Count()
})
});
foreach (var data in processedData)
{
Console.WriteLine(data.Category);
foreach (var element in data.Bugs)
Console.WriteLine(" " + element.Priority + " = " + element.Count);
}
You can do it like this
var retList = (from dbc in db.Companies
where dbc.IsVerified && dbc.SellsPCBs && !dbc.IsDeleted && !dbc.IsSpam && dbc.IsApproved
select new
{
name = dbc.CompanyName,
compID = dbc.CompanyID,
state = dbc.State,
city = dbc.City,
businessType = dbc.BusinessType
}).GroupBy(k => k.state).ToList();
List<dynamic> finalList = new List<dynamic>();
foreach (var item in retList)
{
finalList.Add(item.GroupBy(i => i.city));
}