繁体   English   中英

使用 RxJS Observable 管道确保所有 id 都是唯一的

[英]Assure all ids are unique with RxJS Observable pipe

我有一个可观察的,我想在它解析之前对其进行修改,或者使用map管道或类似的东西来确保groups数组中的所有 id 都是唯一的。 如果cats出现两次,则第二次出现应该变为cats-1cats-2等。这些字段用于填充 HTML id 属性,因此我需要确保它们始终是唯一的。

{ 
  title: 'MyTitle',
  description: 'MyDescription', 
  groups: [
     {
        id: 'cats',
        title: 'SomeTitle'
     },
     {
        id: 'dogs',
        title: 'SomeTitle'
     },
     {
        id: 'octupus',
        title: 'SomeTitle'
     },
     {
        id: 'cats',
        title: 'SomeTitle'
     },
  ]

}

使用 RxJs observable 我的代码如下所示:

getGroups() { 
  return this.http.get(ENDPOINT_URL)
}

我能够使用带有setmap运算符来实现这一点,但我的一部分感觉这不是正确的管道,因为数组是嵌套的。

getGroups() { 
  return this.http.get(ENDPOINT_URL).pipe(
     map(data => {
        const groupIds = new Map();

        data.groups.map(group => {
           if (!groupIds.get(group.id)) {
              groupIds.set(group.id, 1)
           } else {
             const updatedId = (groupIds.get(group.id) || 0) + 1;

             groupIds.set(group.id, updatedId);
             group.id = `${group.id}-${updatedId}`
           }

           return group
        }

        return data;
     }
  )
}

有没有更有效的方法可以使用更合适的管道进行此操作? 我担心在 observable 解决冲突时,这会变得非常低效并显着延迟内容的渲染。 截至今天,我无法修改从 API 返回的实际内容,因此很遗憾这不是一个选项。

你可以尝试这样的事情:

import { of, map } from 'rxjs';
import { findLastIndex } from 'lodash';

of({
  title: 'MyTitle',
  description: 'MyDescription',
  groups: [
    {
      id: 'cats',
      title: 'SomeTitle',
    },
    {
      id: 'dogs',
      title: 'SomeTitle',
    },
    {
      id: 'cats',
      title: 'SomeTitle',
    },
    {
      id: 'octupus',
      title: 'SomeTitle',
    },
    {
      id: 'cats',
      title: 'SomeTitle',
    },
  ],
})
  .pipe(
    map((data) => ({
      ...data,
      groups: data.groups.reduce((acc, group) => {
        const lastElementIndex = findLastIndex(acc, (accGroup) => accGroup.id.startsWith(group.id));
        
        if (lastElementIndex === -1) {
          return [...acc, group];
        }

        const lastElement = acc[lastElementIndex];
        const lastNameNumerator = lastElement.id.split('-')[1];

        return [
          ...acc,
          {
            ...group,
            id: `${group.id}-${lastNameNumerator ? +lastNameNumerator + 1 : 1}`,
          },
        ];
      }, []),
    }))
  )
  .subscribe(console.log);

Stackblitz: https ://stackblitz.com/edit/rxjs-kcxdcw?file=index.ts

如果唯一的要求是让 id 唯一,您可以通过将数组索引附加到每个元素的 id 来确保唯一性。

getGroups() { 
  return this.http.get(ENDPOINT_URL).pipe(
    map(data => {
      const groups = data.groups.map(
        (g, i) => ({...g, id: `${g.id}-${i}`})
      );
      
      return { ...data, groups };
    })
  );
}

组的输出:

// groups: Array[5]
//   0: Object
//     id    : "cats-0"
//     title : "SomeTitle"
// 
//   1: Object
//     id    : "dogs-1"
//     title : "SomeTitle"
// 
//   2: Object
//     id    : "cats-2"
//     title : "SomeTitle"
// 
//   3: Object
//     id    : "octupus-3"
//     title : "SomeTitle"
// 
//   4: Object
//     id    : "cats-4"
//     title : "SomeTitle"

这是一个小StackBlitz

老实说,你所拥有的可能很好。 这是另一种稍微简单的方法。 它首先使用 reduce 来创建组的对象字面量。 如果你对外部依赖开放,你可以使用 Ramda 的 groupWith 函数来产生相同的结果。 然后它使用 flatMap 来展平组。 如果数组中只有一项,则按原样返回,否则元素将使用新的 id 进行变异。

getGroups() { 
  return this.http.get(ENDPOINT_URL).pipe(
    map(data => Object.values(
         data.groups.reduce((acc, cur) => {
           (acc[cur.id] || (acc[cur.id] = [])).push(cur);
           return acc;
         },
         {} as Record<string | number, [] as GroupType[])
       ).flatMap(grp => (grp.length === 1)
         ? grp
         : grp.map((x, i) => ({ ...x, id: `${x.id}-${i + 1}`)))
  )
}

另一个

map((data:any) => {

  //create an array in the way [{id:"cats",data:[0,3]}{id:"dogs",data:[1]..]
  const keys=data.groups.reduce((a:any,b:any,i:number)=>{
    const el=a.find(x=>x.id==b.id)
    if (el)
      el.data=[...el.data,i]
    else
      a=[...a,({id:b.id,data:[i]})]
    return a
  },[])

  //loop over groups, if keys.data.length>1 ...
  data.groups.forEach((x,i)=>{
    const el=keys.find(key=>key.id==x.id)
    if (el.data.length>1)
      x.id=x.id+'-'+(el.data.findIndex(l=>l==i)+1)
  })
  return data;
})

或者

map((data:any) => {

  //create an object keys {cats:[0,3],dogs:[1]....
  const keys=data.groups.reduce((a:any,b:any,i:number)=>{
    if (a[b.id])
      a[b.id]=[...a[b.id],i]
    else
      a[b.id]=[i]
    return a
  },{})

  //loop over groups, if keys[id].length>0 ...
  data.groups.forEach((x,i)=>{
    if (keys[x.id].length>1)
      x.id=x.id+'-'+(keys[x.id].findIndex(l=>l==i)+1)
  })
  return data;
})

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM