首页 > 解决方案 > 如何以真正的功能风格使用 RxJS 制作复杂的“地图”和“平面”?

问题描述

RxJS 和 TypeScript 提供了强大的函数式编程能力。因此,当它有意义时,我会尝试练习它。但是今天我未能以函数式风格编写相当简单的映射逻辑。我仍然相信可以用真正实用的方式来描述它,但要简洁、优雅且易于阅读。这样的代码会是什么?

这是一个 stackblitz 游乐场: https ://stackblitz.com/edit/rxjs-functional-challenge?file=index.ts

完整的源代码副本也在剧透之下。

import { Observable, of, identity } from 'rxjs';
import { map, tap, mergeMap} from 'rxjs/operators';

interface TimeWindow{
  Start: number,
  End: number
}

interface Schedule{
  Monday: TimeWindow[],
  Tuesday: TimeWindow[],
}

let schedule$: Observable<Schedule>; // input varible
let timeWindows$: Observable<{Day: string, Time: string}[]>; // result variable

schedule$ = of({
  Monday: [{Start: 9, End: 11}, {Start: 15, End: 17}],
  Tuesday: [{Start: 8, End: 10}, {Start: 14, End: 16}],
});

// conversion
// how to rewrite it into 100% functional style, yet still easy to read?

timeWindows$ = schedule$.pipe(
  map(schedule => [
    ... mapToTimeWindows('Monday', schedule.Monday),
    ... mapToTimeWindows('Tuesday', schedule.Tuesday,)
  ])
);

function mapToTimeWindows(day: string, timeWindows: TimeWindow[]): {Day: string, Time: string}[]{
  const convertTime = (hour: number) => hour.toString().padStart(2, '0') + ':00';

  return timeWindows.map(item => ({
    Day: day,
    Time: convertTime(item.Start) + ' - ' + convertTime(item.End)      
  }));
}

// expected result
// converted to console in functional style

timeWindows$.pipe(
  mergeMap(identity),
  map(item => item.Day + ':  ' + item.Time),
  tap(console.log)
).subscribe();


/*
Monday:  09:00 - 11:00
Monday:  15:00 - 17:00
Tuesday:  08:00 - 10:00
Tuesday:  14:00 - 16:00
*/

标签: javascripttypescriptfunctional-programmingrxjs

解决方案


链接到操场

const convertTime = (hour: number) => hour.toString().padStart(2, "0") + ":00";

timeWindows$ = schedule$.pipe(
  map(schedule =>
    Object.keys(schedule).flatMap(weekDay =>
      schedule[weekDay].map(item => ({
        Day: weekDay,
        Time: convertTime(item.Start) + " - " + convertTime(item.End)
      })
     )
    )
  )
);

推荐阅读