Home > Software engineering >  Pattern matching on one field of collection
Pattern matching on one field of collection

Time:08-27

Let's say that I have a class called car like this:

        public class Car
        {
            public int Id { get; set; }

            public State State { get; set; }
        }

        public abstract record State(DateTime UpdatedAt)
        {
            protected State() : this(DateTime.UtcNow)
            {
            }
        }

        public record New : State;

        public record Damaged(int DamagedParts, string Description) : State;

and I fetched a list of cars with state damaged from database. It is a IReadOnlyCollection. How can I easily get properties of DamagedState (damaged parts and description) without iterating through the list? Can I use pattern matching for this?

Amount of fetched Cars can be up to 50k.

CodePudding user response:

You cannot do this without iterating through the list. You will not have to iterate explicitly by using LINQ, but LINQ does iterate internally.

Since you cars list contains only cars with state Damaged, we don't need a Where clause:

List<(int CarId, int DamagedParts, string Description)> damaged = cars
    .Select(c => 
      (CarId: c.Id, ((Damaged)c.State).DamagedParts, ((Damaged)c.State).Description))
    .ToList();

This returns a list of tuples with the required info.

Or, easier:

List<(int CarId, Damaged Damage)> damaged = cars
    .Select(c => (CarId: c.Id, Damage: (Damaged)c.State))
    .ToList();

You can also defer execution and not call .ToList(). This will return an IEnumerable<T> that will iterate the original cars list without storing it in a new collection.

I do not see how pattern matching can help in this case.

If you want to be able to quickly select the damage by car Id:

Dictionary<int, Damaged> damageDict = cars
    .ToDictionary(c => c.Id, c => (Damaged)c.State);

if (damageDict.TryGetValue(5, out var damage)) {

}
  • Related