【问题标题】:angular remove duplicates in an observable角度删除可观察对象中的重复项
【发布时间】:2020-11-16 08:46:25
【问题描述】:

在这个 mat-option 中,我试图显示来自我订阅的 observable 的数据。

   <mat-option *ngFor="let option of (filteredCustomer | async)?.Items"
   [value]="option" (onSelectionChange)="searchDest($event)">
   {{option.Cityname}} 
   </mat-option>

observable的名字是filteredCustomer。

现在在 mat 选项中,我尝试显示城市名称。结果就是这样。

Los Angeles
Boston
Detroit
Los Angeles
Washington
Los Angeles

如你所见,我有重复。

是否可以删除重复项(如 sql 中的 distinct)?

我的 observable 来自这个 ts 文件:

public filterCity() {
 var parameters = new CitySearchParameters(100, 0);
 parameters.City = this.city;    
 this.filteredCustomer = this.customerService.get(parameters);
 if (typeof (this.city) == "object") {
  var curCity: any = this.city;
  this.city = curCity.City;
 }
}

谢谢

【问题讨论】:

  • 预期输出是什么?只是一个字符串列表?

标签: angular duplicates observable distinct


【解决方案1】:

您可以使用 Array#filterArray#findIndex 来删除数组中的重复项。

// credit: https://stackoverflow.com/a/36744732/6513921
private uniqueArray(target: Array<any>, property: any): Array<any> {
  return target.filter((item, index) =>
    index === target.findIndex(t => 
      t[property] === item[property]
    )
  );
}

然后,您可以使用 map 运算符从控制器中的可观察对象“捕获”发射,并在将它们渲染到模板中之前删除重复项

public filterCity() {
  var parameters = new CitySearchParameters(100, 0);
  parameters.City = this.city;
  this.filteredCustomer = this.customerService.get(parameters).pipe(
    map(customer => ({
      ...customer,
      Items: uniqueArray(customer.Items, 'Cityname')  // <-- remove duplicates by `Cityname` property
    }))
  );
  if (typeof (this.city) == "object") {
    var curCity: any = this.city;
    this.city = curCity.City;
  }
}

扩展运算符... 用于在来自可观察对象的发射中保留除Items 属性数组之外的其他属性。它已被修改以删除重复项。

【讨论】:

  • 它工作正常。这样我就有了一个专用的方法(你称为 uniqueArray 的那个),将来会有用。非常感谢。
【解决方案2】:

你可以使用RxJS reduce 操作符来保持你的异步管道工作,像这样,假设你正在删除基于.Cityname 属性的重复项

public filterCity() {
  var parameters = new CitySearchParameters(100, 0);
  parameters.City = this.city;
  this.filteredCustomer = this.customerService.get(parameters).pipe(
    reduce((list, val) => {
      if (!list.length) return [val]
      const foundIndex = list.findIndex((item) => item.cityname === val.cityname);
      if (foundIndex === -1) {
        list.push(val);
      }

      return list;
    }, [])
  );
  if (typeof(this.city) == "object") {
    var curCity: any = this.city;
    this.city = curCity.City;
  }
}

【讨论】:

    【解决方案3】:

    Set 对象允许您存储任何类型的唯一值,无论是原始值还是对象引用。

    因此您可以转换列表,重复项将被删除。

        let list = [...new Set(this.filteredCustomer)];
    

    另一种使用过滤器的方法

    let chars = ['A', 'B', 'A', 'C', 'B'];
    
    let uniqueChars = chars.filter((c, index) => {
        return chars.indexOf(c) === index;
    });
    
    console.log(uniqueChars); // results = [ 'A', 'B', 'C' ]
    
    

    【讨论】:

    • 使用 Set 方法我有这个错误:没有重载匹配这个调用。重载 1 of 2,'(iterable?: Iterable): Set',给出了以下错误。 'Observable' 类型的参数不可分配给'Iterable' 类型的参数。 “Observable”类型中缺少属性“[Symbol.iterator]”,但在“Iterable”类型中是必需的。重载 2 of 2,'(values?: readonly any[]): Set',给出了以下错误。 'Observable' 类型的参数不可分配给'readonly any[]' 类型的参数。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2021-10-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-02-22
    • 1970-01-01
    • 2018-12-20
    相关资源
    最近更新 更多