Tengo una variedad de devices . Para cada dispositivo, quiero establecer el nombre predeterminado ( "DeviceX" - X es un número de secuencia), pero es posible que algunos de ellos ya estén en uso/ocupados. Entonces necesito hacer una solicitud para verificar si el nombre ya existe ( ifDeviceExists() devuelve verdadero o falso en respuesta). Si el nombre ya está ocupado, debe aumentar el número y una vez más enviar una solicitud para verificar si ese nombre (por ejemplo, "Dispositivo2") ya existe. Si el nombre no está ocupado, debe establecer el nombre de ese dispositivo (device.name = "Device2").
Por ejemplo, nombres de dispositivos ocupados: "Device2" y "Device4" . Luego, los nombres de los nuevos dispositivos creados deben ser: "Device1", "Device3", "Device5", "Device6" ... Por lo tanto, la matriz de devices debe ser: [{name: "Device1"}, {name: "Device3"}, {name: "Device5"}, {name: "Device6"}, ... ]
El principal problema para mí aquí es que verificar si el nombre existe es una acción asíncrona y no sé cómo manejar eso (dónde enviar la solicitud y cuándo suscribirse) ¿Alguien podría ayudarme con eso?
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); } }) }Como no proporcionó información adicional, brindé una solución según mi comprensión y suposición
ifDeviceExists devolvía Observable<boolean> y devolvía true/false según el estado de disponibilidad Como ifDeviceExists devolviera observable, entonces para usar su resultado dentro de la tubería necesitamos usar observable de orden superior , en este caso usé concatmap
Acerca concatMap
Para indexar el valor de índice de concatMap utilizado
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)