【问题标题】:How can I sort the result of an observable in a multiple way?如何以多种方式对 observable 的结果进行排序?
【发布时间】:2021-09-06 11:41:07
【问题描述】:

我有一个可观察的 TableData 类型,它返回一组表行和列。 用户可以从 select 中选择要排序的一组列(行所指的)(默认情况下按升序排列)。 例如,如果用户输入“员工”和“项目”,我应该先按员工对行进行排序,然后再按每个员工的升序对项目进行排序。

类类型:


export interface TableColumn {
  value: string;
  label: string;
  hidden: boolean;
  format: (value: any) => string;
}

export interface TableRow {
  [key: string]: any;
}

export interface TableData {
  columns: TableColumn[];
  rows: TableRow[];
}
export class Activity {
  id?: number;
  [HOURS_KEY]: number;
  [DATE_KEY]: string;
  [EMPLOYEE_KEY]: ActivityEmployee;
  [TYPE_KEY]: ActivityType;
  [PROJECT_KEY]?: ActivityProject;
}

export class ActivityEmployee {
  id: number;
  lastName: string;
  firstName: string;
}

假设现在我只想按 Employee 和 Project 排序(所以是一个静态示例),我怎样才能以链式方式排序我得到的 oberables?

我以这种方式调用可观察结果:


tableDataColumns$ = this.activityCollection.groupedEntities$?.pipe(
    map((e) => e.columns)
  );
  tableDataRows$ = this.activityCollection.groupedEntities$?.pipe(
    map((e) => e.rows)
  );

【问题讨论】:

    标签: angular typescript rxjs


    【解决方案1】:
    sortBy = new Subject<[string, string]>();
    
    tableDataRows$ = this.sortBy.pipe(
      startWith(["", ""]),
      switchMap(([sort1, sort2]) =>
        this.activityCollection.groupedEntities$.pipe(
          map(({ rows }) => rows),
          map(rows =>
            !!sort1 ? rows.sort((a, b) => (a[sort1] < b[sort1] ? -1 : 1)) : rows
          ),
          map(rows => (!!sort2 ? this.splitSortRows(rows, sort1, sort2) : rows))
        )
      )
    );
    
    splitSortRows = <T>(rows: T[], splitBy: string, sortBy: string): T[] => {
      const uniqueValues = [...new Set(rows.map(row => row[splitBy]))];
      const splitArray = uniqueValues.map(value =>
        rows.filter(row => row[splitBy] === value)
      );
      return splitArray.reduce(
        (acc, arrSegment) => [
          ...acc,
          ...arrSegment.sort((a, b) => a[sortBy] < b[sortBy] ? -1 : 1),
        ],
        [] as T[]
      );
    };
    

    我们首先声明一个主题,该主题将发出一个表示要排序的两个标签的元组。然后我们按照以下顺序设置管道:

    1. 订阅我们的主题以接收最新的排序标准
    2. 将地图切换到可观察的源数据。
    3. 使用map() 和对象解构来获取我们的rows 数据。
    4. 根据我们的第一个条件对rows 数组进行排序,使用简单的.sort() 完成。
    5. 接下来我们调用一个更复杂的函数来完成子排序。

    至于splitSortRows() 的工作原理:

    1. 创建第一个排序条件的唯一行值数组。
    2. 对于每个唯一的项目,我们将单个数组分解为多个数组。每个子数组组共享我们第一个过滤条件的相同值。
    3. 接下来,我们对每个子数组进行排序,然后将它们连接回一个数组。

    现在,当您的用户单击一个或两个标签进行排序时,您可以在 sortBy 主题中发出这些排序标签。订阅将处理剩下的事情。

    this.sortBy.next(['employee', 'project']);
    // tableDataRows$ should now emit a new array of rows sorted by employee first, and projects second
    

    【讨论】:

    • 谢谢,但是我有 5 列(不是所有的都是数字,有些是字符串),所以这个方法可能太宽泛了
    • 对不起@Man24。我更新了我的答案,所以它会对数字和字符串进行排序。
    猜你喜欢
    • 1970-01-01
    • 2014-11-22
    • 2021-03-16
    • 1970-01-01
    • 2012-12-11
    • 2011-07-27
    • 1970-01-01
    • 1970-01-01
    • 2014-01-08
    相关资源
    最近更新 更多