leora
leora

Reputation: 196669

In C# What is the best way to filter out of this collection?

I have a list of Room objects, each room object has a Building attribute;

 public class Room
{
      public string BuildingName;
      public string Name 
}

I now want to filter my collection where i only take 1 room from each building (I don't care which one)

so for example

 var room = new Room(){BuildingName ="Building 1", Name = "Room 1"};
 var room2 = new Room(){BuildingName ="Building 1", Name = "Room 2"};
 var room3 = new Room(){BuildingName ="Building 2", Name = "Room 3"};
 var room4 = new Room(){BuildingName ="Building 2", Name = "Room 4"};
 var room5 = new Room(){BuildingName ="Building 2", Name = "Room 5"};

 var ListofRooms = new List<Room> {room, room2, room3, room4, room5};

in this case i would want to run this list through a function that would return an array with 2 items (one from each Building)

Upvotes: 3

Views: 202

Answers (2)

educampver
educampver

Reputation: 3005

You could use this approach:

var result = ListofRooms.Distinct(new BuildingEqualityComparer());

And the class BuildingEqualityComparer is as follows:

public class BuildingEqualityComparer : IEqualityComparer<Room>
{
    public bool Equals(Room x, Room y)
    {
        return x.BuildingName.Equals(y.BuildingName);
    }

    public int GetHashCode(Room obj)
    {
        return obj.BuildingName.GetHashCode();
    }
}

This approach is actually rarelly used because you need to make an implementation of IEqualityComparer which is a PITA, but it's just another way of achieving what you need, so if you like it or find it simpler, use it!!!

Upvotes: 0

Ani
Ani

Reputation: 113442

LINQ is pretty convenient for this sort of task:

var result = ListofRooms.GroupBy(room => room.BuildingName)
                        .Select(buildingGroup => buildingGroup.First())
                        .ToList();

What this does is create a bucket for each building (consisting of the rooms in the building), then select a room from each bucket, before finally materializing the selected rooms into a collection.

Some tangential points:

  1. Standard C# naming conventions dictate that local variables should be named in camelCase (listOfRooms), not PascalCase(ListofRooms).
  2. If you like, you can get rid of the parantheses for the parameterless constructor in the object-initializers, like this: new Room { BuildingName = "Building 1", Name = "Room 1" }

If you don't want to use LINQ for this, I would do:

var seenBuildingNames = new HashSet<string>();
var result = new List<Room>();

foreach(var room in ListofRooms)
{
    if(seenBuildingNames.Add(room.BuildingName))
    {
        // First time we are encountering this building; add room to result.
        result.Add(room);
    }
}

Upvotes: 4

Related Questions