簡體   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