我必须返回所有不包含猫或猫头鹰的房间。如果一个房间里有一种被禁止的动物,它就不能被添加到我们想要返回的列表中。它将是一个服务的方法,被用作API端点。
public async Task<List<Room>> GetRoomForRabbitOwners()
{
}
public enum PetType : byte
{
Cat,
None,
Rabbit,
Owl
}
下面是数据结构:
[
{
"id": 1,
"capacity": 5,
"residents": [
{
"id": 2,
"name": "Tom",
"houseType": 2,
"petType": 1,
"room": null
},
{
"id": 4,
"name": "Nicol",
"houseType": 2,
"petType": 3,
"room": null
}
]
},
{
"id": 2,
"capacity": 5,
"residents": [
{
"id": 3,
"name": "Rambo",
"houseType": 2,
"petType": 2,
"room": null
}
]
},
{
"id": 3,
"capacity": 1010,
"residents": []
},
{
"id": 4,
"capacity": 10,
"residents": []
},
{
"id": 5,
"capacity": 15,
"residents": []
}
]
很多次,我设法写一个表达式看起来不错,但最后它失败了,返回一个列表"租户"(类),既然只有"房间"(类)允许的。
似乎你的帖子需要更多的信息。也就是说,租客和居民是什么意思?此外,您的数据结构将一个房间定义为包含住户。你想把房间还给住客吗?
这里有一个解决方案,它返回一个没有猫的房间列表;猫头鹰:
void Main()
{
var data = File.ReadAllText(Path.Combine(
Environment.GetFolderPath(Environment.SpecialFolder.Desktop),
"data.json"));
var allRooms = JsonConvert.DeserializeObject<List<Room>>(data);
var filteredRooms = GetRoomForRabbitOwners(allRooms).Dump();
}
public List<Room> GetRoomForRabbitOwners(List<Room> rooms)
{
return rooms
.Where(room => !room.Residents.Any(resident =>
(PetType)resident.PetType == PetType.Cat ||
(PetType)resident.PetType == PetType.Owl))
.ToList();
}
public enum PetType : byte
{
Cat = 1,
None = 2,
Rabbit = 3,
Owl = 4
}
public class Resident
{
public int Id { get; set; }
public string Name { get; set; }
public int HouseType { get; set; }
public byte PetType { get; set; }
public int? Room { get; set; }
}
public class Room
{
public int Id { get; set; }
public int Capacity { get; set; }
public List<Resident> Residents { get; set; }
}
有Rooms
和Residents
。房间和居民之间存在一对多的关系:每个房间有零个或多个居民,每个居民都是恰好一个房间中的宠物。
把你的问题分成两个子问题是明智的:
- 阅读你的源代码。获取"有0个或多个住户的房间"的序列
- 给出一个房间序列和他们的居民,给我所有既没有猫也没有猫头鹰作为居民的房间。
.
class Resident
{
public int Id {get; set;}
public string Name {get; set;}
public HouseType HouseType {get; set;}
public PetType PetType {get; set;}
... // etc
}
class Room
{
public int Id {get; set;}
public int Capacity {get; set;}
public virtual ICollection<Resident> Residents {get; set;}
}
我选择居民作为virtual ICollection<Resident>
有几个原因。首先,它不是一个列表,因为Resident[2]
没有一个明确的含义:你不确定猫是否在狗之前。ICollection<...>
包含所有你需要处理居民的方法:你可以添加/删除/计数居民。该方法是虚拟的,因此实际读取源代码以创建Rooms的过程可以自由决定他们想要使用哪个特定的类来存储resident (List<Resident>
或Resident[...]
,或其他东西)。
下面的程序将把你的来源读入"Rooms with their resident"的序列:
public IEnumerable<Room> GetRoomsWithResidents()
{
...
}
您可能更熟悉序列的数据格式,因此您可以实现它。单独的过程的好处是,它将很容易进行单元测试。易于更改:如果以后您决定使用数据库或csv文件来存储Rooms。更改将是最小的。
要求给出一个房间序列,以及一个禁止的PetTypes序列,给出所有没有这些PetTypes居民的房间
我将把它写成一个扩展方法,这样你就可以把它和其他LINQ方法交织在一起。如果您不熟悉扩展方法,可以考虑阅读《扩展方法揭秘》。
public IEnumerable<Room> ToRoomsWithoutForbiddenPets(this IEnumerable<Room> rooms,
IEnumerable<PetType> forbiddenPets)
{
// TODO: check input not null. Raise exceptions
return rooms.Where(room => !room.Residents
.Select(resident => resident.PetType)
.Intersect(forbiddenPets)
.Any());
}
换句话说:在房间序列中的每个房间中,只保留满足以下要求的房间:从房间中的每个居民中获取PetType。这是PetTypes的一个序列。将此序列与forbiddenPetTypes相交。只有当这个交集没有任何元素(为空)时,才保留Room。
用法:
IEnumerable<PetType> forbiddenPets = new PetType[] {PetType.Cat, PetType.Owl}
IEnumerable<Room> validRooms = GetRoomsWithResidents()
.ToRoomsWithoutForbiddenPets(forbiddentPets);
方法ToRoomsWithoutForbiddenPets
也易于理解,易于单元测试,易于维护。