How do I write this in LINQ? - c#

Im sure there is some way to write this code in Linq. But I'm new to LINQ and don't know how to do it?
Here is the code:
List<IEntityMITARBEITER> leiter = new List<IEntityMITARBEITER>();
foreach (IEntityMITARBEITER mitarbeiter in mit)
{
foreach (IEntityREF_SCHULLUNG refs in refSchullung)
{
if (refs.Id_person == mitarbeiter.Id_mit)
{
leiter.Add(mitarbeiter);
}
}
}

leiter = mit.Where(x => refSchullung.Any(y => y.Id_person == x.Id_mit)).ToList();
(in case the co-worker doesn't appear in more courses.)

var selectedMitarbeiter = mit
.Where(m => refSchulung.Any(s => s.Id_person == m.Id_mit));
leiter.AddRange(selectedMitarbeiter.ToList());

why do you want re-write it using LINQ? What you have done is ok:it is very readable and much faster than it would be in LINQ
If you really want to use LINQ I can suggest you to install ReSharper which will convert it for you.
http://blogs.jetbrains.com/dotnet/2009/12/resharper-50-preview-loops-2-linq/

Using Join() would make a lot of sense in this case:
var joinQuery = mit.Join(refSchullung, x => x.Id_mit, x => x.Id_Person, (x, y) => x);
leiter.AddRange(joinQuery.ToList());
This will match up each element of the two sequences where the keys match, and select a single item for each case.

Related

two foreach in linq?

...I've tried something but I got the "Local sequence cannot be used in LINQ to SQL implementations of query operators except the Contains operator." exception.
I'm talking about this:
Query = Query.Where(t => this.SysTextBox.Text.CSL2Array().All(ss => t.SysName.Contains(ss)));
I'm kind of new at this, but I kept trying to make it work. Thank you in advance!
You should be able to do the query after ToList:
Query = Query.ToList<TagsDeleted>()
.Where(t => this.SubSystemTextBox.Text.CSL2Array().All(ss => t.SubsystemName.Contains(ss)))
.AsQueryable<TagsDeleted>();
But that is not easy to read, I would refactor to the following to make it clear that "I create a list, and want to remove some items":
var words = this.SubSystemTextBox.Text.CSL2Array();
var list = Query.ToList<TagsDeleted>();
list.RemoveAll(t => !words.All(word => t.SubsystemName.Contains(word)));
Query = list.AsQueryable<TagsDeleted>();
var arr = this.SubSystemTextBox.Text.CSL2Array();
var notContained = Query.Where(td=>arr.Any(ss => !td.SubsystemName.Contains(ss)));
Query = Query.Except(notContained);
You can figure this out how to make it in one line, this was just to be clear.

Lambda Max and Max and Max

Quick and probably easy Lambda question:
I have a restaurant with reviews.
I want to query for the one with the:
Max(AverageRating)
And the Max(ReviewCount)
And the Max(NewestReviewDate)
And the Min(DistanceAway)
Something like this:
var _Result = AllRestaurants
.Max(x => x.AverageRating)
.AndMax(x => x.ReviewCount)
.AndMax(x => x.NewestReviewDate)
.AndMin(x => x.DistanceAway);
Now, I know that is pseudo code. But it describes it perfectly!
Of course, in multiple statements, this is simple.
Just wondering if this is possible in one statement without killing the readability.
Thank you in advance. I know some of you love the query questions!
You can't have multiple maxes or mins, that doesn't make sense.
You'll need some kind of heuristic like:
.Max(x => x.AverageRating * x.ReviewCount - x.DaysSinceLastReview - x.DistanceAway)
Perhaps this would do?
var bestRestaurant = AllRestaurants
.OrderByDescending(r => r.AverageRating)
.ThenByDescending(r => r.ReviewCount)
.ThenByDescending(r => r.NewestReviewCount)
.ThenBy(r => r.DistanceAway)
.FirstOrDefault();
You'd need to change the order of the statements to reflect which is the most important.
An alternative to having some weighted heuristic is to order by AverageRating, then ReviewCount, then ...
Something like this should work:
var _Result = AllRestaurants
.OrderByDescending(x => x.AverageRating)
.ThenByDescending(x => x.ReviewCount)
.ThenByDescending(x => x.NewestReviewDate)
.ThenByDescending(x => x.DistanceAway);
// using *Descending so you get the higer-valued ones first
Consider something like this...
List<RestaurantRecord> _Restaurants;
public RestaurantRecord Best()
{
return _Restaurants.Where(
x =>
x.AverageRating >= _BestRating &&
x.ReviewCount >= _MinReviews &&
x.Distance <= _MaxDistance)
.GetFirstOrDefault();
}
That being said, using a lambda in this case will have maintainability consequences down the road. It would be a good idea to refactor this, such that if other criteria appear in the future (e.g.: smartphone access? Cuisine type?), your app can be more easily modified to adapt to those.
On that note, a slightly better implementation might be something like:
public RestaurantRecord Best()
{
IQueryable temp = _Restaurants.Clone();
temp = temp.Where( x => x.AverageRating >= _BestRating );
temp = temp.Where( x => x.ReviewCount >= _MinReviews );
// ...snip...
return temp.GetFirstOrDefault();
}
I hope this sets you on the right track. :)
If I'm understanding your question, I think the best approach is going to be writing individual statements as you mention...
var HighestRating = AllRestaurants.Max(x => x.AverageRating);
var HighestReviewCount = AllRestaurants.Max(x => x.ReviewCount);
var LatestReviewDate = AllRestaurants.Max(x => x.NewestReviewDate);
var ShortestDistanceAway = AllRestaurants.Min(x => x.DistanceAway);
Retrieving various maxes and mins from a single Linq query would get pretty messy and I'm not sure there'd be any advantage with efficiency, either.

A LINQ question: map query expression to c# code

How do I translate the following query expression to corresponding C# code? Thanks.
var list1 = (from ol in orderedList
from er in ol.Er
from rd in er.Rd
where rd.ftr != ""
select ol).ToList<CRInfo>();
It would translate to something like this:
var list1 = orderedList.SelectMany(ol => ol.Er, (ol, er) => new { ol, er })
.SelectMany(z => z.er.Rd, (z, rd) => new { z, rd })
.Where(z2 => z2.rd.frt != "")
.Select(z2 => z2.z.ol)
.ToList<CRInfo>();
The "z" and "z2" bits are transparent identifiers, used by the C# compiler to propagate multiple range variables through the query.
You may want to download LINQPad, which I believe lets you translate query expressions like this very easily.
Well, aside from the obvious fact that your code is already C# code...
I assume you want to obtain the actual Enumerable method calls? If so, you could just compile it and throw it into Reflector.

Replacing nested foreach with LINQ; modify and update a property deep within

Consider the requirement to change a data member on one or more properties of an object that is 5 or 6 levels deep.
There are sub-collections that need to be iterated through to get to the property that needs inspection & modification.
Here we're calling a method that cleans the street address of a Employee. Since we're changing data within the loops, the current implementation needs a for loop to prevent the exception:
Cannot assign to "someVariable" because it is a 'foreach iteration variable'
Here's the current algorithm (obfuscated) with nested foreach and a for.
foreach (var emp in company.internalData.Emps)
{
foreach (var addr in emp.privateData.Addresses)
{
int numberAddresses = addr.Items.Length;
for (int i = 0; i < numberAddresses; i++)
{
//transform this street address via a static method
if (addr.Items[i].Type =="StreetAddress")
addr.Items[i].Text = CleanStreetAddressLine(addr.Items[i].Text);
}
}
}
Question:
Can this algorithm be reimplemented using LINQ? The requirement is for the original collection to have its data changed by that static method call.
Update: I was thinking/leaning in the direction of a jQuery/selector type solution. I didn't specifically word this question in that way. I realize that I was over-reaching on that idea (no side-effects). Thanks to everyone! If there is such a way to perform a jQuery-like selector, please let's see it!
foreach(var item in company.internalData.Emps
.SelectMany(emp => emp.privateData.Addresses)
.SelectMany(addr => addr.Items)
.Where(addr => addr.Type == "StreetAddress"))
item.Text = CleanStreetAddressLine(item.Text);
var dirtyAddresses = company.internalData.Emps.SelectMany( x => x.privateData.Addresses )
.SelectMany(y => y.Items)
.Where( z => z.Type == "StreetAddress");
foreach(var addr in dirtyAddresses)
addr.Text = CleanStreetAddressLine(addr.Text);
LINQ is not intended to modify sets of objects. You wouldn't expect a SELECT sql statement to modify the values of the rows being selected, would you? It helps to remember what LINQ stands for - Language INtegrated Query. Modifying objects within a linq query is, IMHO, an anti-pattern.
Stan R.'s answer would be a better solution using a foreach loop, I think.
I don't like mixing "query comprehension" syntax and dotted-method-call syntax in the same statement.
I do like the idea of separating the query from the action. These are semantically distinct, so separating them in code often makes sense.
var addrItemQuery = from emp in company.internalData.Emps
from addr in emp.privateData.Addresses
from addrItem in addr.Items
where addrItem.Type == "StreetAddress"
select addrItem;
foreach (var addrItem in addrItemQuery)
{
addrItem.Text = CleanStreetAddressLine(addrItem.Text);
}
A few style notes about your code; these are personal, so I you may not agree:
In general, I avoid abbreviations (Emps, emp, addr)
Inconsistent names are more confusing (addr vs. Addresses): pick one and stick with it
The word "number" is ambigious. It can either be an identity ("Prisoner number 378 please step forward.") or a count ("the number of sheep in that field is 12."). Since we use both concepts in code a lot, it is valuable to get this clear. I use often use "index" for the first one and "count" for the second.
Having the type field be a string is a code smell. If you can make it an enum your code will probably be better off.
Dirty one-liner.
company.internalData.Emps.SelectMany(x => x.privateData.Addresses)
.SelectMany(x => x.Items)
.Where(x => x.Type == "StreetAddress")
.Select(x => { x.Text = CleanStreetAddressLine(x.Text); return x; });
LINQ does not provide the option of having side effects. however you could do:
company.internalData.Emps.SelectMany(emp => emp.Addresses).SelectMany(addr => Addr.Items).ToList().ForEach(/*either make an anonymous method or refactor your side effect code out to a method on its own*/);
You can do this, but you don't really want to. Several bloggers have talked about the functional nature of Linq, and if you look at all the MS supplied Linq methods, you will find that they don't produce side effects. They produce return values, but they don't change anything else. Search for the arguments over a Linq ForEach method, and you'll get a good explanation of this concept.
With that in mind, what you probaly want is something like this:
var addressItems = company.internalData.Emps.SelectMany(
emp => emp.privateData.Addresses.SelectMany(
addr => addr.Items
)
);
foreach (var item in addressItems)
{
...
}
However, if you do want to do exactly what you asked, then this is the direction you'll need to go:
var addressItems = company.internalData.Emps.SelectMany(
emp => emp.privateData.Addresses.SelectMany(
addr => addr.Items.Select(item =>
{
// Do the stuff
return item;
})
)
);
To update the LINQ result using FOREACH loop, I first create local ‘list’ variable and then perform the update using FOREACH Loop. The value are updated this way. Read more here:
How to update value of LINQ results using FOREACH loop
I cloned list and worked NET 4.7.2
List<TrendWords> ListCopy = new List<TrendWords>(sorted);
foreach (var words in stopWords)
{
foreach (var item in ListCopy.Where(w => w.word == words))
{
item.disabled = true;
}
}

Lambda expression to grab all values inside a Dictionary

I have a LINQ query which returns all the values inside a Dictionary, conditional upon something:
var apps =
from entry in shape.Decorators
where entry.Value == DecoratorLayoutStyle.App
select entry.Key;
shape.Decorators is a
Dictionary<Shape, DecoratorLayoutStyle>
Is there something terser, and/or can I use a combination of lambdas or something?
var apps = shape.Decorators
.Where(x=>x.Value == DecoratorLayoutStyle.App)
.Select(x=>x.Key);
I think yours is just as fine.
That looks plenty terse to me, I guess you could use the extension functions instead of the from/select linq syntax, but that wouldn't be too different.
More imporantly, I'm not sure you want terser. The current format is very readable, and clearly documents exactly what you're trying to do.
var apps = shape.Decorators
.Where(e => e.Value == DecoratorLayoutStyle.App)
.Select(e => e.Key);
Do you think this is terser?
Personally I prefer the query syntax when I have more than one LINQ operator all the operators I use can be translated to it.
var apps = Shape.Decorators.Where(x => x.Value == DecoratorLayoutStyle.App)
.Select(x => x.Key);
Just to be different.
var apps = shape.Decorators.Keys
.Where(k => shape.Decorators[k] == DecoratorLayoutStyle.App);

Categories