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 :)
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'm trying to check the difference between a master list of items in c# vs an array of lists.
Not quite sure how to build this logic in an efficient way.
Example:
My master list of items is: var MasterOrderIDs = {1,2,3,4}
Then I have an Customer/Order object where it's storing the Customer ID along with its OrderID
CustomerID|OrderID
1 | 1
1 | 2
1 | 3
1 | 4
1 | 5
2 | 1
2 | 2
2 | 3
2 | 4
2 | 5
2 | 6
3 | 2
3 | 3
3 | 4
I want to return an array which has the CustomerID along with the OrderIDs where the difference of the MasterOrderIDs has a difference of less than 2.
Something like:
var OrderDifferences = new Dictionary<int, List<int>>();
So in the case of the Customer/Order, I want to return:
{[1, [5]], [3, [1]}
This is because for CustomerID 1, there is a Order ID 5, which is less than 2 differences. Likewise with CustomerID 3, there is a Order ID 1, which appears in MasterOrderIDs and is less than 2 differences.
How can I create such a check?
Ina real-life scenario I will have big data so wondering what would be the best efficient way of doing it.
Based on the information that we got I can think of two relatively small optimizations. So my disclaimer is that the basic approach is still brute force and maybe there is a smarter way to extract the information but we can still perform some checks in order to exclude some of the uneccessary data.
Small optimization 1
We are looking for Customers who compared to the the master list of orders have one more or one less order at most. In other words, based on your example for
var MasterOrderIDs = {1,2,3,4}
a Customer with 5 orders like customerOrders = { 7, 8, 9, 10, 11 } is still potentially valid but customer with 6 orders customerOrders = { 7, 8, 9, 10, 11, 12 } is not.
The same for the bottom number. A Customer with 3 orders is also potentially valid customerOrders = { 7, 8, 9 } but a customer with less the two orders customerOrders = { 7, 8 } is not.
So based on this we can perform our first small optimization filering customers who have more than MasterOrderIDs.Count() + 2 orders or with less than MasterOrderIDs.Count() - 2
Small optimization 2
Even if we are in the appropriate range of orders we want to make sure that our orderIds overlap. We can allow only 1 order which is present in one of the lists and not present in the other. Basically this is not exactly an optimization, but this is second criteria based on which we can construct our query.
Which is:
First seed some data:
class Order
{
public int CustomerId { get; set; }
public int OrderId { get; set; }
public static List<Order> Seed()
{
return new List<Order>
{
new Order { CustomerId = 1, OrderId = 1},
new Order { CustomerId = 1, OrderId = 2},
new Order { CustomerId = 1, OrderId = 3},
new Order { CustomerId = 1, OrderId = 4},
new Order { CustomerId = 1, OrderId = 5},
new Order { CustomerId = 2, OrderId = 1},
new Order { CustomerId = 2, OrderId = 2},
new Order { CustomerId = 2, OrderId = 3},
new Order { CustomerId = 2, OrderId = 4},
new Order { CustomerId = 2, OrderId = 5},
new Order { CustomerId = 2, OrderId = 6},
new Order { CustomerId = 3, OrderId = 2},
new Order { CustomerId = 3, OrderId = 3},
new Order { CustomerId = 3, OrderId = 4}
};
}
}
Then set the initial data:
var masterList = new List<int> { 1, 2, 3, 4 };
var upperBorder = masterList.Count() + 2;
var bottomBorder = masterList.Count() - 2;
var orders = Order.Seed();
And finally extract the records that we need:
var ordersWithinRange = orders
.GroupBy(o => o.CustomerId)
.Where(x => x.Count() < upperBorder && x.Count() > bottomBorder && x.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(x.Select(o => o.OrderId))).Count() < 2)
.ToDictionary(d => d.Key, d => d.Select(o => o.OrderId).Except(masterList).Concat(masterList.Except(d.Select(o => o.OrderId))).ToList());
Again. This will take a lot of computing time but I think it's a little bit faster than a sequence of for loops filtering one thing at a time.
This question already has answers here:
C# List grouping and assigning a value
(2 answers)
Closed 6 years ago.
I need help to solve this.
I have used Console Application to solve this and I am stuck.
Every row in ORDER needs to have an unique value inside a group med same GROUP-value. The Max-value on ORDER inside the group need to be Count of Rows -1 and Min value has to be 0. The sorting doesnt matter.
It only needs to be an UNIQUE value between min and max.
Example: 012345 or 041532
ID GROUP VALUE ORDER
1 1 10 0
2 1 2 0
3 2 1 0
4 3 2 0
5 3 6 0
6 3 1 0
7 3 9 0
GROUP 1 have 2(-1) Rows, ORDER value has to be 0-1.
GROUP 2 have 1(-1) Rows, ORDER value has to be 0.
GROUP 3 have 4(-1) Rows, ORDER value has to be 0-3.
End Result:
ID GROUP VALUE ORDER
1 1 10 0
2 1 2 1
3 2 1 0
4 3 2 0
5 3 6 1
6 3 1 3
7 3 9 2
Here is the properties i have used.
public class OrderRow
{
public int ID { get; set; }
public int GROUP { get; set; }
public int VALUE { get; set; }
public int ORDER { get; set; }
}
new OrderRow {ID = 1, GROUP = 1, VALUE = 10, ORDER = 0},
new OrderRow {ID = 2, GROUP = 1, VALUE = 2, ORDER = 0},
new OrderRow {ID = 3, GROUP = 2, VALUE = 1, ORDER = 0},
new OrderRow {ID = 4, GROUP = 3, VALUE = 2, ORDER = 0},
new OrderRow {ID = 5, GROUP = 3, VALUE = 6, ORDER = 0},
new OrderRow {ID = 6, GROUP = 3, VALUE = 1, ORDER = 0},
new OrderRow {ID = 7, GROUP = 3, VALUE = 9, ORDER = 0},
THANKS
I'd go like follows:
List<OrderRow> orders = new List<OrderRow>() {
new OrderRow { ID = 1, GROUP = 1, VALUE = 10, ORDER = 0 },
new OrderRow { ID = 2, GROUP = 1, VALUE = 2, ORDER = 0 },
new OrderRow { ID = 3, GROUP = 2, VALUE = 1, ORDER = 0 },
new OrderRow { ID = 4, GROUP = 3, VALUE = 2, ORDER = 0 },
new OrderRow { ID = 5, GROUP = 3, VALUE = 6, ORDER = 0 },
new OrderRow { ID = 6, GROUP = 3, VALUE = 1, ORDER = 0 },
new OrderRow { ID = 7, GROUP = 3, VALUE = 9, ORDER = 0 },
};
foreach (var item in orders.GroupBy(order => order.GROUP))
{
int order = 0;
foreach (var item2 in item)
{
item2.ORDER = order++;
}
}
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
Please do not respond using lamba. I have found similar threads but still need help.
I am trying to display the names from the employees table that are not employees of the currently selected manager.
My two sql tables are structured like this but this is fake data
Employees:
pk name
1 bob
2 sam
3 greg
4 kip
5 jill
6 kelly
7 chris
ExpenseTeamMembers:
pk expMgrPk empPk
1 7 2
2 7 5
3 7 1
4 3 6
5 3 4
So if the the current selected (mgr variable) is 3 I want to get the names of all empPks in the employees table except for 6, 4. (kelly, kip) Right now unselectedEmps = sam, jill, bob instead of all 5 of other names from the employees table.
var unselectedEmps = (from u in db.employees
join o in db.expenseTeamMembers on u.pk equals o.empPk
where o.expMgrPk != mgr
select u.name).ToList();
lstAvailable.DataSource = unselectedEmps;
After our extended discussion, I think what you want is this.
from u in db.Employees
where !(from e in db.ExpenseTeamMembers
where e.expMgrPk == selectedMgr.pk
select e.empPk).Contains(u.pk)
select u.Name
The problem is that you are doing an inner join when you actually need a left outer join
See this SO question
I have tried the following and it is giving the correct output. Please try it:
List<Employees> emps = new List<Employees>();
emps.Add(new Employees { PK = 1, Name = "bob" });
emps.Add(new Employees { PK = 2, Name = "sam" });
emps.Add(new Employees { PK = 3, Name = "greg" });
emps.Add(new Employees { PK = 4, Name = "kip" });
emps.Add(new Employees { PK = 5, Name = "jill" });
emps.Add(new Employees { PK = 6, Name = "kelly" });
emps.Add(new Employees { PK = 7, Name = "chris" });
List<ExpenseTeamMembers> etm = new List<ExpenseTeamMembers>();
etm.Add(new ExpenseTeamMembers { empPK = 2, ExpMgrPK = 7, PK = 1 });
etm.Add(new ExpenseTeamMembers { empPK = 5, ExpMgrPK = 7, PK = 2 });
etm.Add(new ExpenseTeamMembers { empPK = 1, ExpMgrPK = 7, PK = 3 });
etm.Add(new ExpenseTeamMembers { empPK = 6, ExpMgrPK = 3, PK = 4 });
etm.Add(new ExpenseTeamMembers { empPK = 4, ExpMgrPK = 3, PK = 5 });
var query = from t in
(
from emp in emps
join o in etm on emp.PK equals o.empPK into j
from k in j.DefaultIfEmpty()
select new { Name = k == null ? string.Empty : emp.Name })
where t.Name != string.Empty
select t.Name;