我有一个devices
数组。对于每个设备,我想设置默认名称("DeviceX"
- X是序列号),但其中一些可能已经使用/占用。所以我需要发出一个请求来检查名称是否已经存在(ifDeviceExists()
在响应中返回真或假)。如果该名称已被占用,则应增加该数量并再次发送请求以检查该名称(例如device2)是否已存在。如果name未被占用,则应该设置该设备的名称(device.name = "Device2")。
举例占用设备名称:"Device2"
、"Device4"
。那么新创建的设备的名称应该是:"Device1", "Device3", "Device5", "Device6"
…所以devices
数组应该是:[{name: "Device1"}, {name: "Device3"}, {name: "Device5"}, {name: "Device6"}, ... ]
对我来说,这里的主要问题是检查名称是否存在是async动作,我不知道如何处理(在哪里发送请求,何时订阅)有人能帮我吗?
ifDeviceExists(name: string): Observable<boolean> {
return [ 'Device2', 'Device4' ].includes(name) ? of(true) : of(false);
}
findNextDeviceName(indexWrapper: { index: number }, device: Device):
Observable<{ device: Device, name:string; index: number }> {
let currentName: string;
let currentIndex = indexWrapper.index;
return interval(0).pipe(
// send requests to check name sequentially until it returns false and filter passes event
// to first() operator which will stop interval loop, NOTE: if ifDeviceExists() allways returns true,
// there will be infinite loop
concatMap(interval => {
currentIndex = currentIndex + interval;
currentName = `Device${currentIndex}`;
return this.ifDeviceExists(currentName);
}),
filter(exists => !exists),
first(),
map(() => ({device, name: currentName, index: currentIndex})),
)
}
renameDevices(){
const devices = [{id: 101}, {id: 102}, {id: 103}, {id: 104}];
// this object keeps last index and allows to change it between concatMap iterations
const indexWrapper = {index: 1};
from(devices).pipe(
concatMap(device => this.findNextDeviceName(indexWrapper, device)),
map(result => {
indexWrapper.index = result.index + 1;
result.device.name = result.name;
return result.device;
}),
toArray()
).subscribe({
next: (devices) => {
console.log('Devices with names', devices);
}
})
}
由于您没有提供额外的信息,所以我根据我的理解和假设提供了解决方案
- 我假设
ifDeviceExists
返回Observable<boolean>
和返回true/false
根据可用性状态 - 假设期望新数组附带设备名称
作为ifDeviceExists
返回的可观察对象,所以为了在管道中使用它的结果,我们需要使用高阶可观察对象在本例中,我使用concatmap
对
concatMap
用于索引使用concatMap
索引值
devices = [
{ id: 1, status: 'available' },
{ id: 2, status: 'used' },
{ id: 3, status: 'available' },
{ id: 4, status: 'occupied' },
{ id: 5, status: 'available' },
{ id: 6, status: 'available' },
{ id: 7, status: 'available' },
];
ngOnInit(): void {
this.setDevicesName().subscribe(console.log);
}
ifDeviceExists(deviceId: number): Observable<boolean> {
let device = this.devices.find((d) => d.id === deviceId);
return of(device.status === 'used' || device.status === 'occupied');
}
setDevicesName(): Observable<any> {
return from(this.devices).pipe(
concatMap((device, index) =>
this.ifDeviceExists(device.id).pipe(
tap(() => index++),
filter((res) => !res),
map((res) => {
device['name'] = 'Device' + index;
return device;
})
)
),
toArray()
);
}
const reserved = ["device2", "device5"]; //any list that contains device<X> elements
const devices = [{},{},{},{},{},{},{},{},{},{}];
let num = 0;
for (let device of devices) {
if (!reserved.includes("device" + num)) {
device.name = 'device' + num
};
num++
}
console.log(devices)