Communities

Writing
Writing
Codidact Meta
Codidact Meta
The Great Outdoors
The Great Outdoors
Photography & Video
Photography & Video
Scientific Speculation
Scientific Speculation
Cooking
Cooking
Electrical Engineering
Electrical Engineering
Judaism
Judaism
Languages & Linguistics
Languages & Linguistics
Software Development
Software Development
Mathematics
Mathematics
Christianity
Christianity
Code Golf
Code Golf
Music
Music
Physics
Physics

Dashboard
Notifications
Mark all as read
Q&A

Update list based on presence of identifier in a second list

+5
−0

In C#, I have two lists and need to mark records in the first based on the second. Here's a sample:

public class Vehicle
{
    public string Make { get; set; }
    public string VIN { get; set; }
    public string Color { get; set; }
    public bool HasRegistration { get; set; } = false;
}

The second list is simply a set of VINs (List<string>) that have been registered. I need to mark all the vehicles in the List<Vehicle> which have their VIN somewhere in the List<string>. This is what I have, and it works, but I am looking for something more LINQ.

foreach(var v in vehicles)
{
    if (vinList.Contains(v.VIN))
    {
       v.HasRegistration = true;
    }
}

I could also do v.HasRegistration = (vinList.Contains(v.VIN));

Can this be done in a single, LINQ statement?

Why does this post require moderator attention?
You might want to add some details to your flag.
Why should this post be closed?

3 comments

Nope. LINQ is about receiving and not mutating. You could use .ForEach though: vehicles.ForEach(v => v.HasRegistration = vinList.Contains(v.VIN)); FoggyFinder‭ about 1 month ago

I.e. in practice you can write vehicles.Select(v => v.HasRegistration = vinList.Contains(v.VIN)).ToArray(); or something but you shouldn't do that. FoggyFinder‭ about 1 month ago

@FoggyFinder, if you make that an answer, I'd be glad to accept it. The fact that it can't be done. I have no desire to be too clever. FrankLuke‭ about 1 month ago

3 answers

+5
−0

This can't be done with the standard library. It's quite common for people who want to do this to define their own extension method

public static void Foreach<T>(this IEnumerable<T> items, Action<T> action)
{
    foreach (var item in items) action(item);
}

which would allow the one-liner

vehicles.Foreach(v => v.HasRegistration |= vinList.Contains(v.VIN));

There doesn't appear to be a consensus on whether this is an elegant and useful extension method or an abomination, so check your local style guide first.


Although it's not strictly an answer to the question, I must also point out that Contains on a list is a linear time operation, and unless you can guarantee that the list will never hold more than about three VINs you should first convert it to a data structure with a fast lookup. E.g.

var vinLookup = vinList.ToHashSet();
vehicles.Foreach(v => v.HasRegistration |= vinLookup.Contains(v.VIN));

If you don't have ToHashSet (in the standard library it's newish) then the implementation is just new HashSet<string>(vinList).

Why does this post require moderator attention?
You might want to add some details to your flag.

0 comments

+4
−0

If you want to be more Linq-like without creating a ForEach method:

vehicles = vehicles
   .Select(
       v =>
          new Vehicle
          {
             Make = v.Make,
             VIN = v.VIN,
             Color = v.Color,
             HsRegistration = vinList.Contains(v.VIN)
          }
   ).ToList();

Here we're treating Vehicle and the list like immutable objects, and creating modified copies rather than mutating them.

Can you make Vehicle a record rather than a class?

record VehicleRecord
{
    internal string Make;
    internal string VIN;
    internal string Color;
    internal bool HasRegistration;
}

If so you can simplify this to:

vehicles = vehicles
    .Select(
         v => v with { HasRegistration = vinList.Contains(v.VIN) }
    ).ToList();
Why does this post require moderator attention?
You might want to add some details to your flag.

0 comments

+3
−0

Adding to Peter Taylor's reply:

The OP requested something "more LINQ". I guess it can't get any "more linq" than... MoreLINQ!

That library also has a ForEach().

If you only need that, maybe it's a bit much to use that lib, but if you like the other stuff in there, too, which I suspect... Was not the question, but hint anyway: their MaxBy, MinBy functions are neat.

Why does this post require moderator attention?
You might want to add some details to your flag.

0 comments

Sign up to answer this question »