1

I have list of objects:

public class SDesc
{
    public string sensorId { get; set; }
    public string address { get; set; }
}

List<SDesc> desc = new List<SDesc>
{
    new SDesc {sensorId = "1234", address =   "Adams22"},
    new SDesc {sensorId = "5555", address =   "Hourton34"},
    new SDesc {sensorId = "4444", address =   "SaintsRoad55"},
    new SDesc {sensorId = "1258", address =   "BerryAve58"},
    new SDesc {sensorId = "52486", address =   "SaintsRoad2"},
    new SDesc {sensorId = "12361", address =   "TomassonRoad"}
}

And also I have IEnumarable of strings:

IEnumarable<string> sId = {"4444","52486","12361"};

from desc list I need to remove records where sensorsId property exists in sId list.

For example for case above the result I want to get is:

List<SDesc> desc = new List<SDesc>
{
    new SDesc {sensorId = "1234", address =   "Adams22"},
    new SDesc {sensorId = "5555", address =   "Hourton34"},
    new SDesc {sensorId = "1258", address =   "BerryAve58"},
}

Here what I tried:

desc.RemoveAll(obj => obj.sensorId == sId);

But it's not works properly because sID is IEnumarable type.

So my question is how to remove items from desc list where sensorsId property exists in sId list?

Matze
  • 5,100
  • 6
  • 46
  • 69
Michael
  • 13,950
  • 57
  • 145
  • 288
  • Basically the same question as [here](http://stackoverflow.com/q/18895751/993547), and [many other questions here](https://www.google.com/search?q=subtract+list+linq+c%23&oq=subtract+list+linq+c%23#q=subtract+list+linq+c%23+site:stackoverflow.com). – Patrick Hofman Mar 13 '17 at 08:59

2 Answers2

3

You need to use Any with it like:

 desc.RemoveAll(obj => sId.Any(x=> x== obj.sensorId ));

As method name suggests it would check if any of the item in sId matches with the item in desc against sensorId, it will remove those items from List<T>.

Ehsan Sajjad
  • 61,834
  • 16
  • 105
  • 160
  • Thanks for post.What if I desc is type of IEnumarable and not List.what is the way to remove items from it? – Michael Mar 13 '17 at 09:09
  • in that case you would need to use `Where()` to filter the results and store reference to new `IEnumberable` something like: `var result = desc.Where(obj => sId.Any(x=> x== obj.sensorId ));` – Ehsan Sajjad Mar 13 '17 at 09:11
2

You can use .Contains() LINQ method to check if a collection contains an item:

desc.RemoveAll(obj => sId.Contains(obj.sensorId));

However, it would lead to multiple enumeration of enumerable sId. It's not a problem in this case since this enumerable is an array in this particular case.

Read more about "possible multiple enumeration":
- Handling warning for possible multiple enumeration of IEnumerable
- Resharper's example code for explaining "Possible multiple enumeration of IEnumerable"

I would recommend converting it to a collection to make sure you enumerate IEnumerable only once.
As suggested by Evk in comments, it is better to use HashSet so that .Contains executes in O(1) time:

List<SDesc> desc = new List<SDesc> {
  new SDesc {sensorId = "1234", address =   "Adams22"},
  new SDesc {sensorId = "5555", address =   "Hourton34"},
  new SDesc {sensorId = "4444", address =   "SaintsRoad55"},
  new SDesc {sensorId = "1258", address =   "BerryAve58"},
  new SDesc {sensorId = "52486", address =   "SaintsRoad2"},
  new SDesc {sensorId = "12361", address =   "TomassonRoad"}
};

IEnumarable<string> sId = {"4444","52486","12361"};
var sIdsSet = new HashSet(sId);

desc.RemoveAll(obj => sIdsSet.Contains(obj.sensorId));
Community
  • 1
  • 1
Yeldar Kurmangaliyev
  • 33,467
  • 12
  • 59
  • 101
  • If convert it to anything, I'd say it should be `HashSet` and not array. – Evk Mar 13 '17 at 09:01
  • @Yeldar Kurmangaliyev: shouldn't you remove negator (!) from your line: `desc.RemoveAll(x => !sIdsArray.Contains(x.sensorId));` Michael needs everything that's not in sId List – tretom Mar 13 '17 at 09:03
  • @Evk Thank you! I missed that performance improvement possibility :) Just have updated my answer. – Yeldar Kurmangaliyev Mar 13 '17 at 09:04