Apply function to some elements of list
I have a list of complex objects ie
class MyObject
{
public bool selected;
public int id;
public string name;
}
List<MyObject> theObjects = functionThatSelectsObjectsFromContainer();
And I have a list from another source that just give me int ids that are in the list of objects
List<int> idList = functionThatReturnsListOfIds();
Now for each of the items in the idList I want to set the selected
property true. I know I can set up a foreach of one list and then search for the matching items in the other list and set it that way, but I was wondering if there's a different way that might be quicker.
Conclusion
I did some testing on all my methods below, as well as un-lucky 's answer, and the fastest of them all was option 2 below, ie
var results = theObjects.Join(idList, o => o.id, id => id, (o, id) => o).ToList();
results.ForEach(o => o.selected = true);
Another way of doing it with Linq, where we iterate around theObjects
and check each one to see if its' id exists in idList
:
1
var result = theObjects.ForEach(o => o.selected = idList.Contains(o.id) ? true : false);
or using Join
and ForEach
, where we first extract the matching items using Join
and then iterate around those items:
2
var results = theObjects.Join(idList, o => o.id, id => id, (o, id) => o).ToList();
results.ForEach(o => o.selected = true);
or, you can use Select
with ForEach
and FirstOrDefault
. This is probably going to be slower than the other 2:
3
theObjects
.Select(o => o.id)
.Where(i => idList.Contains(i)).ToList()
.ForEach(i =>
theObjects.FirstOrDefault(o => o.id == i).selected = true);
I did some testing on the 3 methods I posted, where we have 10000 MyObject
s and 1000 unique ids. I ran each method 1000 times, and then got the mean ElapsedMillliseconds
for each.
The results were
1
8.288 ms
2
0.19 ms
3
57.342 ms
one = 0;
two = 0;
three = 0;
for (var i = 0; i <1000; i++) {
RunTest();
}
oneMean = one / 1000;
twoMean = two / 1000;
threeMean = three / 1000;
where
private void RunTest()
{
ResetData();
var stopwatch = Stopwatch.StartNew();
theObjects.ForEach(o => o.selected = idList.Contains(o.id) ? true : false);
stopwatch.Stop();
one += stopwatch.ElapsedMilliseconds;
ResetData();
stopwatch = Stopwatch.StartNew();
var results = theObjects.Join(idList, o => o.id, id => id, (o, id) => o).ToList();
results.ForEach(o => o.selected = true);
stopwatch.Stop();
two += stopwatch.ElapsedMilliseconds;
ResetData();
stopwatch = Stopwatch.StartNew();
theObjects
.Select(o => o.id)
.Where(i => idList.Contains(i)).ToList()
.ForEach(i =>
theObjects.FirstOrDefault(o => o.id == i).selected = true);
stopwatch.Stop();
three += stopwatch.ElapsedMilliseconds;
}
private void ResetData()
{
theObjects = new List<MyObject>();
idList = new List<int>();
var rnd = new Random();
for (var i=0; i<10000; i++) {
theObjects.Add(new MyObject(){id = i});
}
for (var i=0; i<=1000; i++) {
var r = rnd.Next(0, 1000);
while (idList.Contains(r)) {
r = rnd.Next(0, 10000);
}
idList.Add(r);
}
}
I tested un-lucky 's answer (most upvotes right now) and it got a mean score of 147.676
foreach(var obj in theObjects.Where(o => idList.Any(i=> i == o.id)))
{
obj.selected = true;
}
我认为你可以做这样的事情来做到这一点
foreach(var obj in theObjects.Where(o => idList.Any(i=> i == o.id)))
{
obj.selected = true;
}
在Linq的帮助下,您可以使用Where,ToList和ForEach来实现您所需的行为 -
theObjects.Where(x => idList.Contains(x.id)).ToList().ForEach(y => y.selected = true);
链接地址: http://www.djcxy.com/p/28094.html
上一篇: 多个背景的索引
下一篇: 将函数应用于列表的某些元素