Reputation: 193
I am trying to convert below nested for each loop into Linq. However I am still unable to do it successfully.
var objAct = new List<InformaticsBenchmarkSummary>();
foreach (var item in op)
{
foreach (var lstTp5 in lstTopFive)
{
if (item.UnitOfOperations.ContainsKey(lstTp5.SystemID))
{
var objIbm = new InformaticsBenchmarkSummary();
objIbm.CompanyId = item.CompanyId;
objIbm.CompanyName = item.CompanyName;
objIbm.LocationId = item.LocationId;
objIbm.LocationName = item.LocationName;
objIbm.UnitOfOperations.Add(lstTp5.SystemID,
item.UnitOfOperations[lstTp5.SystemID]);
objAct.Add(objIbm);
}
}
}
Where UnitOfOperations
is of type Dictionary<int,string>()
;
op
is again List<InformaticsBenchmarkSummary>()
lstTopFive
is List<int>()
I tried, something like this but was unsuccessful syntactically
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
let v = new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName
}
.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID])
select v;
Nested loop works perfectly but I think, linq on this will increase performance. Appreciate any help.
Upvotes: 1
Views: 12491
Reputation: 842
May this help U :
var output = from item in op
join lstTp5 in lstTopFive on item.UnitOfOperations.Key equals lstTp5.SystemID
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = item.UnitOfOperations
};
Upvotes: 0
Reputation: 13022
It is impossible in a Linq query-syntax to use the UnitOfOperations.Add
in the select. But you can do it using Method Chain and a SelectMany
method:
var objAcu = (op.SelectMany(item => lstTopFive, (item, lstTp5) => new { item, lstTp5 }) // <- Bad readability
.Where(t => t.item.UnitOfOperations.ContainsKey(t.lstTp5.SystemID))
.Select(t =>
{
var objIbm = new InformaticsBenchmarkSummary
{
CompanyId = t.item.CompanyId,
CompanyName = t.item.CompanyName,
LocationId = t.item.LocationId,
LocationName = t.item.LocationName
};
objIbm.UnitOfOperations.Add(t.lstTp5.SystemID, t.item.UnitOfOperations[t.lstTp5.SystemID]);
return objIbm;
})).ToList();
If the property UnitOfOperations
has a public set
, in this case, you can use the query-syntax.
How do you replace 1 foreach
? By a from ... in ...
Then, to replace 2 foreach
, use 2 from ... in ...
var objAct = (from item in op // First foreach loop
from lstTp5 in lstTopFive // Second foreach loop
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
}).ToList();
But I doubt it will increase performance in such an operation.
Anyway, I don't understand what you try to achieve. Because in all items of the output will have one and only one element in the dictionary UnitOfOperations
. Is it really what you want to do?
List<int> systemIdTop5 = lstTopFive.Select(tp5 => tp5.SystemID).ToList();
var objAct = (from item in op
select new InformaticsBenchmarkSummary
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = systemIdTop5.Intersect(item.UnitOfOperations.Keys)
.ToDictionary(systemId => systemId, systemId => item.UnitOfOperations[systemId])
}).ToList();
Upvotes: 2
Reputation: 244948
You're close, but you can't just use a void
returning method in LINQ query like that. (And if it wasn't void
-returning, then v
would be the result of Add()
, which would be most likely wrong.)
If you wanted to create a new Dictionary
for UnitOfOperations
, you could set it the same way as other properties. But if you can't do that (probably because UnitOfOperations
has a private setter) or you don't want to (because UnitOfOperations
is initialized to some value that you want to keep), you can use a lesser known feature of C#: collection initializer inside object initializer:
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
The effect of this code is the same as if you wrote:
createdObject.UnitOfOperations.Add(lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID]);
The only difference is that it's not a statement, it's part of an expression, which means you can use it in a LINQ query.
The whole query would then be:
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations =
{
{ lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] }
}
};
Upvotes: 1
Reputation: 1415
As far as I can tell it is your UnitOfOperations that you're having difficulty with. If it is initialized in the constructor you can use this:
var output = from item in op
from lstTp5 in lstTopFive
where item.UnitOfOperations.ContainsKey(lstTp5.SystemID)
select
new InformaticsBenchmarkSummary()
{
CompanyId = item.CompanyId,
CompanyName = item.CompanyName,
LocationId = item.LocationId,
LocationName = item.LocationName,
UnitOfOperations = { { lstTp5.SystemID, item.UnitOfOperations[lstTp5.SystemID] } }
};
The result is an IEnumerable
, if you want it as a list, call output.ToList()
.
Two side notes:
UnitOfOperations
), but I guess that is desired. In the worst case scenario all items in op
have a UnitOfOperations
that contain all the SystemID
in lstTopFive
giving us a total of op.Count()*lstTopFive.Count()
items in the output
.Upvotes: 1