I have following normal foreach using LINQ query, How can i transform it using Parallel.Foreach
foreach (var i in media.Where(x => x is Video)
{
this.Update(i);
}
How can i do it like
Parallel.ForEach(media,i =>
{
//LINQ
});
First of all, Where(x => x is Video) can be replaced by OfType<Video>().
Second, for fluent syntax it's better to use ParallelEnumerable.ForAll extension method:
media.OfType<Video>()
.AsParallel()
.ForAll(this.Update)
The first argument to Parallel.ForEach is an enumerable, so the obvious way would be:
Parallel.ForEach(media.Where(x => x is Video).OrderBy(x => x.Contains("a")), i =>
{
//this.Update(i);
// commented out because you'll probably want to Invoke it
// depending on what it does exactly.
});
You can do either
Parallel.ForEach(media.Where(x => x is Video), this.Update);
or
media.AsParallel().Where(x => x is Video).ForAll(this.Update);
Adding an order in a parallel process makes no sense here.
Try this :
Parallel.ForEach<Video>(media.Where(x => x is Video), i =>
{
this.Update(i);
};
Well ... basically like you've said ... but ... keep in mind that if you need to order the results and you're acting on that, it's not really parallel ...
The linq parallel foreach will partition your collection and work on it at the same time, which you also need to take into account making sure your this.Update can work with multiple users without messing up .
So, what's the question really ?
Related
Hello I try To Convert My old code to new version with Linq but i have problem for do it
old :
foreach (var item in NetworkInterface.GetAllNetworkInterfaces())
{
if (item.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
{
lstTrace.Items.Add(item.Name);
}
}
to this:
lstTrace.Items.Add(
NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.FirstOrDefault()
.Name
);
But it just returns one result.
How can I get all found items?
I would not recommend to create 'one-liner' code which spans for 5 lines and mixes both data selection and filling list view. Make both things easy to read and understand. Split (1) retrieving and filtering data with (2) assigning data to list view:
var ethernetInterfaceNames =
from i in NetworkInterface.GetAllNetworkInterfaces()
where i.NetworkInterfaceType == NetworkInterfaceType.Ethernet
select i.Name;
foreach(var name in ethernetInterfaceNames)
lstTrace.Items.Add(name);
I would also move getting ethernet interface names to separate method or layer. Thus you will split business logic and presentation logic. You can use AddRange here, but it willl not make your code any simpler:
lstTrace.Items.AddRange(ethernetInterfaceNames.Select(n => new ListViewItem(n)).ToArray())
I believe simple foreach loop is far more readable.
You need to use the AddRange method to add multiple items and then you just need to use select to get the Names of your nics.
Your current code is using FirstOrDefault which will only ever return a single value (the first) from your enumerable.
lstTrace.Items.AddRange(
NetworkInterface
.GetAllNetworkInterfaces()
.Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.Select(nic => nic.Name)
.ToArray()
);
Additionally xanatos's comment on your question is worth repeating here. Your previous code worked fine, and was readable. Doing this with LINQ isn't going to make your code faster and I would probably say makes it harder to read if anything. While the above code should work I would seriously consider just keeping your original code.
lstTrace.Items.AddRange(NetworkInterface.GetAllNetworkInterfaces().Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet).Select(a => a.Name).ToArray());
You are only getting one, because you are only asking for one: FirstOrDefault will give you the first member of the sequence or the type's default value if its empty.
What you need to do is project the sequence to what you really need using Select:
lstTrace.Items
.AddRange(NetworkInterface.GetAllNetworkInterfaces()
.Where(nic => nic.NetworkInterfaceType == NetworkInterfaceType.Ethernet)
.Select(item => item.Name));
Here is an example on how to use AddRange
var projects = multi.Read<ProjectDto>();
var projectAct = multi.Read<ProjectActivity>();
foreach (var project in projects)
{
project.ProjectActivities = new List<ProjectActivity>();
project.ProjectActivities.AddRange(projectAct.Where(x => x.ProjectId == project.ProjectId));
}
Note: One cannot use the addrange on a data type IEnumerable only on the data type list.
I have the following two LINQ statements which set different values in the same item in a list
List<MyClass> myList = GetList();
myList.Where(x => x.Name == "someName").Select(x => x.MyArray = someList.ToArray()).ToList();
myList.Where(x => x.Name == "someName").Select( x => x.AnotherValue = GetValue()).ToList();
Is it possible to combine this so both are set in the one expression?
myList
.Where(x => x.Name == "someName")
.ToList()
.ForEach(x => {
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
});
Why are you calling ToList() at the end of each of those expressions and discarding the result?
Also, Jon Skeet is right that this is an abuse of LINQ, and especially so in your original form: It's explicit that LINQ expressions aren't even necessarily expected to be fully enumerated. The fact that you needed those ToList() calls to make anything happen should have given you a grave and queasy sense that you were misusing a language feature. When you have to do something weird to use your chosen construct instead of the usual way of doing it, finish getting it to work (because weird is cool), and then go back and redo it the boring, lame way before you check it in.
What advantage do you see in the LINQ + ForEach() version above, compared to this version?
foreach (var x in myList.Where(x => x.Name == "someName"))
{
x.MyArray = someList.ToArray();
x.AnotherValue = GetValue();
}
The old-style loop version is shorter, instantly understandable because it's the default idiom, and IMO cleaner. You don't have to do everything with LINQ.
N.B., ForEach() isn't LINQ; it's a member of List<T>. That's why you have to call ToList() to use it.
Just use the lambda operator to pass an entire lambda expression defined inside a
{...} block:
myList.Where(x => x.Name == "someName").Select(x => { x.MyArray = someList.ToArray(); x.AnotherValue = GetValue(); return x;}).ToList();
foreach (var invitation in PendingContactList.CollectionContent)
{
if (!invitation.Contact.incoming)
{
contactInvitationsSent.Add(invitation);
}
}
PendingContactList is a list.
Something like that if contactInvitationsSent is List<T>:
contactInvitationsSent.AddRange(
PendingContactList.CollectionContent.Where(item => !item.Contact.incoming)
);
In case of contactInvitationsSent is not a List<T> and we don't have AddRange method we have to use Add, it seem that Linq is of little help in that case:
foreach(var invitation in PendingContactList.CollectionContent
.Where(item => !item.Contact.incoming))
contactInvitationsSent.Add(invitation);
You can use the following, although it is not guarranteed to give you any performance boost.
contactInvitationSent.AddRange(PendingContactList.CollectionContent
.Where(i => !i.Contact.incoming);
Just for you information, you can also install plugins like ReSharper.
And yes, the price and performance of the tool just does not always compensate for the features it provides. However, questions like thise one can be avoided :-)
There are also some free alternative available. For example the power tools.
http://visualstudiogallery.msdn.microsoft.com/3a96a4dc-ba9c-4589-92c5-640e07332afd
Just read more about resharper etc, goodluck!
try something like :
contactInvitationsSent = PendingContactList.CollectionContent
.Where(x => x.Contact.incoming == false)
.Select(x => x).ToList();
Linq is awesome and very simple notation.
You have to use following syntax.
var demo = (from n in PendingContactList.CollectionContent where n.incoming==false select n).ToList();
I am trying to convert this code to linq:
foreach (var printer in printers)
{
if (printer.Installed)
installedPrinters.Add(printer);
}
I am new to Linq and would appreciate pointers on how it works when iterating through a collection.
printers.Where(printer => printer.Installed)
.ToList()
.ForEach(printer => installedPrinters.Add(printer));
Note the need to call ToList() before ForEach (see Lambda Expression using Foreach Clause).
Also note that while this works, your original code is probably easier to read... LINQ is cool but don't feel obligated to use it for everything :)
If you are just trying to create a new list, you could always just do:
var installedPrinters = printers.Where(p => p.Installed).ToList();
If you are adding to a list that may already have items in it, then you could try:
installedPrinters.AddRange(printers.Where(p => p.Installed));
Assuming your installedPrinters is actually a collection that supports AddRange such as List.
So first use a Where to filter the Installed==true, then run over them with ForEach:
printers.Where(p => p.Installed).ForEach(p => installedPrinters.Add(p));
foreach (var printer in printers.Where (p => p.Installed) { installedPrinters.Add(printer); }
Try this
printer.Where(x => x.Installed).ToList()
.ForEach(
p=>
{
installedPrinters.Add(p)
}
);
Here's the c# code that I have:
private double get806Fees (Loan loan)
{
Loan.Fee.Items class806;
foreach (Loan.Fee.Item currentFee in loan.Item.Fees)
{
if (currentFee.Classification == 806) class806.Add(currentFee);
}
// then down here I will return the sum of all items in class806
}
Can I do this using linq? If so, how? I have never used linq and i've read in several places that using linq instead of a foreach loop is faster... is this true?
Similar to some existing answers, but doing the projection in the query, to make the Sum call a lot simpler:
var sum = (from fee in loan.Items.Fees
where fee.Classification == 806
select fee.SomeValueToSum).Sum();
loan.Item.Fees.
Where(x => x.Classification == 806).
Sum(x => x.SomeValueProperty)
Whether it is faster or not is debatable. IMO, both complexities are the same, the non-LINQ version may be faster.
var q =
from currentFee in loan.Item.Fees
where currentFee.Classification == 806
select currentFee;
var sum = q.Sum(currentFee => currentFee.Fee);
private double get806Fees(Loan loan)
{
return load.Item.Fees.
Where(f => f.Classification == 806).
Sum(f => f.ValueToCalculateSum);
}
I'm assuming here that ValueToCalculateSum is also a double. If it's not then you have to convert it before it is returned.
All of the answers so far are assuming that you're summing up loan.Fees. But the code you actually posted calls Items.Add() to add each Item in loan.Fees.Items to an Items object, and it's that Items object (and not loan.Fees, which is also an Items object) that you say you want to sum up.
Now, if Items is just a simple collection class, then there's no need to do anything other than what people are suggesting here. But if there's some side-effect of the Add method that we don't know about (or, worse, that you don't know about), simply summing up a filtered list of Item objects might not give you the results you're looking for.
You could still use Linq:
foreach (Loan.Fee.Item currentFee in loan.Item.Fees.Where(x => x.Classification == 806)
{
class806.Add(currentFee);
}
return class806.Sum(x => x.Fee)
I'll confess that I'm a little perplexed by the class hierarchy implied here, though, in which the Loan.Item.Fees property is a collection of Loan.Fee.Item objects. I don't know if what I'm seeing is a namespace hierarchy that conflicts with a class hierarchy, or if you're using nested classes, or what. I know I don't like it.