This question already has an answer here:
Closed 10 years ago.
Possible Duplicate:
Sorting an IEnumerable in LINQ
Is it possible to sort this one by not using .ToList()?
Please see codes below.
The code below will result to this output.
{ id = 1, name = "sample 1", list = {'a','f','d'}},
{ id = 5, name = "sample 1", list = {'a','f','c'}},
{ id = 2, name = "sample 1", list = {'g','b'}},
{ id = 4, name = "sample 1", list = {'i','e','h'}},
{ id = 6, name = "sample 1", list = {'d','b','c'}},
{ id = 3, name = "sample 1", list = {'h','i','c'}},
Thanks
RJ
IEnumerable<extra> eList = new List<extra>()
{
new extra{ id = 1, text = "a"},
new extra{ id = 2, text = "g"},
new extra{ id = 3, text = "i"},
new extra{ id = 4, text = "e"},
new extra{ id = 5, text = "f"},
new extra{ id = 6, text = "d"},
new extra{ id = 7, text = "c"},
new extra{ id = 8, text = "h"},
new extra{ id = 9, text = "b"}
};
IEnumerable<sample> sam = new List<sample>()
{
new sample{ id = 1, name = "sample 1", list = new List<int>{1,5,6}},
new sample{ id = 2, name = "sample 2", list = new List<int>{2,9}},
new sample{ id = 3, name = "sample 3", list = new List<int>{8,3,7}},
new sample{ id = 4, name = "sample 4", list = new List<int>{3,4,8}},
new sample{ id = 5, name = "sample 5", list = new List<int>{1,5,7}},
new sample{ id = 6, name = "sample 6", list = new List<int>{6,9,7}}
};
var sorted = (from d1 in sam
select new
{
name = d1.name,
id = d1.id,
list =
(
from d2 in d1.list
join e in eList on d2 equals e.id
select e.text
).OrderBy(item => item).ToList()
}).OrderBy(item => item.list.FirstOrDefault());
Maybe ThenBy will do it?
var sorted = (from d1 in sam
select new
{
name = d1.name,
id = d1.id,
list =
(
from d2 in d1.list
join e in eList on d2 equals e.id
select e.text
).OrderBy(item => item
}).ThenBy(item => item.list.FirstOrDefault());
I misunderstood the question. Why not just remove the ToList? You probably want to have .ToList() though to prevent sorting each time you access the collection.
I've just tested your original code without 'ToList' and it sorts the items AND the 'extras' just fine.. Could you elaborate what exactly you want to achieve? Proof:
result of your original code with ToList:
1 "sample 1" a d f
5 "sample 5" a c f
2 "sample 2" b g
6 "sample 6" b c d
3 "sample 3" c h i
4 "sample 4" e h i
result of your code without ToList:
1 "sample 1" a d f <-- adf is sorted
5 "sample 5" a c f <-- also sorted
2 "sample 2" b g <-- and here too
6 "sample 6" b c d <-- yep
3 "sample 3" c h i <-- it is!
4 "sample 4" e h i <-- ...
^
|
\ aabbce is sorted, too
looks identical to me :)
As for the general idea, the small problem the same written in LINQ syntax without that "ToList" is that JOIN would be executed lazily, once per item, and each time it would build the mapping/join from scratch, while it is perfectly cacheable and reusable. Below, in expanded syntax, I explicitly pre-create the mapping only once, then all the other lazy queries without any materializations use share the same mapping. This way it may be several times faster and use less memory:
var mapping = eList.ToDictionary(x => x.id, x=>x.text);
var temps = sam.Select(s =>
new {
id = s.id,
name = s.name,
stringlist = s.list.Select(id => mapping[id]).OrderBy(str => str)
});
var result = temps.OrderBy(t => t.stringlist.FirstOrDefault());
Try this:
var sorted = (from d1 in sam
select new
{
name = d1.name,
id = d1.id,
list =
(
from d2 in d1.list
join e in eList on d2 equals e.id
select e.text
)
}).OrderBy(item => item.list.OrderBy(i => i).FirstOrDefault());
Related
I have two lists of elements that differ only on the IsTemporalPaymentTerm boolean field.
I want to use LINQ to compare the two lists, entry by entry, and produce a third list that has, for each entry, the one where IsTemporalPaymentTerm = true, and if there isn't one, then I want the one where IsTemporalPaymentTerm = false.
Here's some sample code:
var allResults = db.PaymentTerms
.AsQueryable()
.Where(y => y.WorkDate == date
&& y.ProjectID == ProjectID
&& y.CompanyID == CompanyID
&& y.PayeeID == PayeeID);
//TABLE WITH ONLY TEMPORAL PAYMENT TERMS
var onlyTemporalResults = allResults.Where(x => x.IsTemporalPaymentTerm);
//TABLE WITH ONLY NON-TEMPORAL PAYMENT TERMS
var nonTemporalResults = allResults.Where(x => !x.IsTemporalPaymentTerm);
So, basically what I want is to compare onlyTemporalResults against nonTemporalResults , and get a final list that has either the temporal payment term, OR the non-temporal payment term if no temporal payment term could be found.
Pseudo code example:
List<PaymentTerms> TemporalPaymentTerms = new List<PaymentTerms>();
PaymentTerm unnaprovedPT1 = new PaymentTerm { PayeeID = 1, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false };
PaymentTerm unnaprovedPT2 = new PaymentTerm { PayeeID = 2, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false };
TemporalPaymentTerms.Add(unnaprovedPT1);
TemporalPaymentTerms.Add(unnaprovedPT2);
List<PaymentTerms> NonTemporalPaymentTerms = new List<PaymentTerms>();
PaymentTerm approvedPT1 = new PaymentTerm { PayeeID = 2, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = true};
PaymentTerm approvedPT1 = new PaymentTerm { PayeeID = 3, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = true};
//LINQ query that merges both lists goes here.
//FINAL EXPECTED RESULT:
List<PaymentTerms> FinalList = [
{PayeeID = 1, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false},
{PayeeID = 2, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false},
{PayeeID = 3, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = true}
];
I know this can be done iterating over the two lists (temporal and non-temporal Payment Terms), and then comparing them, but I guess my question is:
Can this be done, more efficiently and in a more elegant way, using a single LINQ query? Maybe a certain form of join that I am missing? Conditional Where clauses?
So far I have failed to see the answer. Thanks in advance!
Is this what you're looking for?
static void Main(string[] args)
{
RunPaymentTermsTest();
Console.WriteLine("Done!");
Console.ReadLine();
}
private static void RunPaymentTermsTest()
{
var temporalPaymentTerms = new List<PaymentTerm>
{
new PaymentTerm { PayeeID = 1, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false },
new PaymentTerm { PayeeID = 2, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = false }
};
var nonTemporalPaymentTerms = new List<PaymentTerm>()
{
new PaymentTerm { PayeeID = 2, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = true },
new PaymentTerm { PayeeID = 3, CompanyID = 2, ProjectID = 3, IsTemporalPaymentTerm = true }
};
var toAdd = temporalPaymentTerms
.Where(x =>
!nonTemporalPaymentTerms.Any(y =>
y.CompanyID == x.CompanyID &&
y.PayeeID == x.PayeeID &&
y.ProjectID == x.ProjectID))
.ToList();
var results = nonTemporalPaymentTerms;
results.AddRange(toAdd);
foreach (var result in results.OrderBy(x => x.PayeeID).ThenBy(x => x.CompanyID).ThenBy(x => x.ProjectID))
{
Console.WriteLine(
$"PayeeID: {result.PayeeID}, CompanyID: {result.CompanyID}, ProjectID: {result.ProjectID}, IsTemporalPaymentTerm: {result.IsTemporalPaymentTerm}");
}
}
I have 2 tables and i want to match up 2 Id values.
First table
Id - 1, 2, 3, 4, 5
DepartmentId - 2, 4, 5, 2, 1
Second table
Id- 1, 2, 10, 30, 40
I want to match up first table's Id's with second table's Id's so i can get DepartmentId values.
I need to get this virtual result:
Id- 1, 2, 10, 30, 40
DepartmentId -2, 4, null, null, null
Here is my code:
for (int i = 0; i < model1.Count(); i++)
{
model1[i].DepartmentId= model2.FirstOrDefault(k => k.Id== model1[i].Id).DepartmentId;
}
I get this error:
An exception of type 'System.NullReferenceException' occurred in
IYP.UserInterfaceLayer.dll but was not handled in user code
I think loop fails because of it can't find 10, 30, 40 Id values. If my Id values are same in 2 tables( Id = 1,2,3,4,5) loop works.
How can i do this with Linq?
You are basically looking for Left Join in LINQ. Try this:-
var query = from emp2 in Employee2
join emp1 in Employee1
on emp2.Id equals emp1.Id into allEmployees
from result in allEmployees.DefaultIfEmpty()
select new
{
ID = emp2.Id,
DeptID = result == null ? "No Department" : result.DepartmentId.ToString()
};
Where I have used following types:-
var Employee1 = new[]
{
new { Id = 1, DepartmentId = 2 },
new { Id = 2, DepartmentId = 4 },
new { Id = 3, DepartmentId = 5 },
new { Id = 4, DepartmentId = 2 },
new { Id = 5, DepartmentId = 1 },
};
var Employee2 = new[]
{
new { Id = 1 },
new { Id = 2 },
new { Id = 10 },
new { Id = 30 },
new { Id = 40 },
};
Complete Working Fiddle.
You should use the Join LINQ extension method. In the form of query syntax (which I believe is more readable for this case) it will look like:
var matchedValues =
from second in model2
join first in model1
on second.Id equals first.Id
into temp
from tempFirst in temp.DefaultIfEmpty()
select
new
{
second.Id,
DepartmentId = tempFirst == null ? null : tempFirst.DepartmentId
};
You join on the Id property and for any value you don't find in the model1, you use a default (DefaultIfEmpty call). Then you choose the resulting DepartmentId based on the join result.
try this
List<long> idlist=model2.tolist().select(t=>t.Id);
List<long> depIdList=model1.where(t=>idlist.contains(t.id)).toList();
I am going to assume that model1 and model2 are both IEnumerable. In that case the following should work.
var result = from x in model2
select
new Model1Type {DepartamentId = x,
Value=
model1.FirstOrDefault(y=>y.DepartamentId==x)
.Select(y=>y.Value)};
This is called Lamq :D
Hope this helps :)
This question already has answers here:
How to intersect list in c#?
(3 answers)
Closed 8 years ago.
I have following 2 list of Item objects in c#:
public class Item
{
public int Id { get; set; }
public List<string> Orders { get; set; }
}
List<Item> items1 = new List<Item>() {
new Item() { Id = 1, Code = 23, Orders = new List<string>() { "A", "B" }},
new Item() { Id = 2, Code = 24, Orders = new List<string>() { "C", "D" }}
};
List<Item> items2 = new List<Item>() {
new Item() { Id = 1, Code = 23, Orders = new List<string>() { "E", "F" }},
new Item() { Id = 2, Code = 24, Orders = new List<string>() { "G", "H" }}
};
I want to merge the Item objects from both lists whose Id and code is same, so the output of above 2 list should be single list with the following entries:
{
new Item() { Id = 1, Code = 23, Orders = new List<string>() { 'A', 'B', 'E', 'F' },
new Item() { Id = 2, Code = 24, Orders = new List<string>() { 'C', 'D', 'G', 'H' }
};
How can i do this in c# using linq ?
You can join both list and then Union their Orders like:
List<Item> combined = (from t in items1
join r in items2 on new { t.Id, t.Code } equals new { r.Id, r.Code }
select new Item
{
Id = t.Id,
Code = t.Code,
Orders = t.Orders.Union(r.Orders).ToList()
}).ToList();
You will get:
If you need your Orders to be concatenated then you can replace Union with Concat. So if your order contains "A", "B" and "A", "F", then with concat you will get "A","B,"A","F" and with Union you will get "A", "B", "F"
var result = from x in items1
join y in items2 on x.Id equals y.Id
select new Item
{
Id = x.Id,
Code = x.Code,
Orders = x.Orders.Concat(y.Orders).ToList()
};
For some reason some records have the same ID. Aim is to list all the whole record which have the same ID. For example, how can group the following records by GroupId using LINQ, and find all records with the same ID and list them all? (thus merging all rows in each group into one)
var list = new List<Record>()
{
new Record() { GroupId = 0, ValueA = 20, ValueB = 300 },
new Record() { GroupId = 1, ValueA = 30, ValueB = 700 },
new Record() { GroupId = 1, ValueA = 40, ValueB = 500 },
new Record() { GroupId = 2, ValueA = 80, ValueB = 300 },
new Record() { GroupId = 2, ValueA = 20, ValueB = 200 },
new Record() { GroupId = 2, ValueA = 20, ValueB = 200 }
};
Expect result is the last 5 records.
Another way is:
var results = (from l in list
group new {l.ValueA, l.ValueB} by l.GroupId
into g
select new {GroupId = g.Key, Values = g.ToList()}).ToList();
If you prefer lambda expression, then
var results = (list.GroupBy(l => l.GroupId, l => new {l.ValueA, l.ValueB})
.Select(g => new {GroupId = g.Key, Values = g.ToList()})).ToList();
This should give you records based on unique GroupIdalong the other values associated.
EDIT
foreach (var result in results)
{
foreach (var value in result.Values)
{
int valueA = value.ValueA;
int valueB = value.ValueB;
}
}
I think you are looking for something similar to this.
Hope it helps.
Answer for "how can group the following records by GroupId using LINQ"
var groupList = list.GroupBy((mRecord) => mRecord.GroupId).ToList();
var groups = list.ToLookup(record => record.GroupId);
var groups1 = groups[1]; //all records with GroupId = 1
I have following Table with records for ActivityLog:
ID, UserId, Category, Created
1 11 DeAssigned 05/10/2012
2 11 LogIn 05/11/2012
3 20 Assigned 06/15/2012
4 11 Assigned 06/10/2012
5 20 DeAssigned 06/13/2012
6 20 Assigned 07/12/2012
7 11 DeAssigned 07/16/2012
8 20 Assigned 08/15/2012
...
now i want to query the Table to create same struct the same Result such as this:
var data = new[] {
new { Month = "05", Assigned = 14, DeAssigned = 5, LogIn=1 },
new { Month = "06", Assigned = 5, DeAssigned = 2, LogIn=0 },
new { Month = "07", Assigned = 50, DeAssigned = 8, LogIn=0 },
new { Month = "08", Assigned = 15, DeAssigned = 1, LogIn=0 }
};
what i have achieved:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by new { l.Created.Value.Month, l.Category }
into groups
orderby groups.Key.Month
select new
{
Month = groups.Key.Month,
Category = groups.Key.Category,
Count = groups.Count()
});
there is not optimal result but count all Activity's grouped by Month:
[0] {Month = 6, Category = Assigned, Count = 2}
[0] {Month = 6, Category = Designed, Count = 1}
[0] {Month = 6, Category = LogIn, Count = 1}
[0] {Month = 7, Category = Assigned, Count = 3}
How can i query my Table to Format my Result in "Horizontal Counted" format?
Or simplier:
var result = (from l in repoA.GetAll()
where l.Created >= System.DateTime.Now.AddYears(-1)
group l by l.Created.Month into groups
orderby groups.Key ascending
select new
{
Month = groups.Key,
Assigned = groups.Where(g => g.Category == "Assigned").Count(),
Deassigned = groups.Where(g => g.Category == "DeAssigned").Count(),
LogIn = groups.Where(g => g.Category == "LogIn").Count()
});