Javascript 如何在视图中仅循环一次对象(single*ngFor)?

Javascript 如何在视图中仅循环一次对象(single*ngFor)?,javascript,angular,typescript,lodash,Javascript,Angular,Typescript,Lodash,我有这个对象,每个属性都有一个数组作为它的值。我只想循环这个对象一次,而不是使用2*ngFor指令,因为它会导致我的应用程序运行缓慢。我也可以用这个对象创建一个数组,但是我仍然希望为每个部分添加一个部分id,如下面的示例所示。谁能给我指出正确的方向吗?提前多谢!这是我的密码 {{group.key}} {{item.name} 注意:我的最终目标是将每个人包装到他们所属的分区中,并为每个分区添加一个id。 例如: 属于a部分的所有用户的列表 属于b部分的所有用户的列表 属于c部分的所有用

我有这个对象,每个属性都有一个数组作为它的值。我只想循环这个对象一次,而不是使用2*ngFor指令,因为它会导致我的应用程序运行缓慢。我也可以用这个对象创建一个数组,但是我仍然希望为每个部分添加一个部分id,如下面的示例所示。谁能给我指出正确的方向吗?提前多谢!这是我的密码


{{group.key}}
{{item.name}
注意:我的最终目标是将每个人包装到他们所属的分区中,并为每个分区添加一个id。 例如:


属于a部分的所有用户的列表
属于b部分的所有用户的列表
属于c部分的所有用户的列表
......
......

使用
*ngFor
无法做到这一点。您可以在组件中准备数据的平面版本,并提供一个1深度数组,以便仅循环一次

AppComponent示例:

import { Component } from "@angular/core";

@Component({
  selector: "app-root",
  templateUrl: "./app.component.html"
})
export class AppComponent {
  
  dataObject = {
    A: [
      { id: 1, name: "Mike", lastname: "asmith" },
      { id: 2, name: "Mary", lastname: "alters" },
      { id: 3, name: "Boris", lastname: "al" }
    ],
    B: [
      { id: 1, name: "Mike", lastname: "bmith" },
      { id: 2, name: "Mary", lastname: "balters" },
      { id: 3, name: "Boris", lastname: "bl" }
    ],
    C: [
      { id: 1, name: "Mike", lastname: "cmith" },
      { id: 2, name: "Mary", lastname: "calters" },
      { id: 3, name: "Boris", lastname: "dl" }
    ],
    D: [
      { id: 1, name: "Mike", lastname: "dmith" },
      { id: 2, name: "Mary", lastname: "dalters" },
      { id: 3, name: "Boris", lastname: "dl" }
    ],
    E: [
      { id: 1, name: "Mike", lastname: "emith" },
      { id: 2, name: "Mary", lastname: "ealters" },
      { id: 3, name: "Boris", lastname: "el" }
    ]
  };

  flatDataObject = [];

  constructor() {
    // Loop through dataObject
    Object.keys(this.dataObject).forEach(k => {
      // Assign key as a `key` attribute to first object in array.
      this.dataObject[k][0].key = k;
      // Push the arrays into one
      this.flatDataObject.push(...this.dataObject[k]);
    });
  }
}
HTML示例:

<div *ngFor="let group of flatDataObject">
  <!-- Check if the object has `key` attribute -->
  <div *ngIf="group.key">
    <!-- If it has `key` attribute: -->
    {{group.key}}
  </div>
  <div>
    {{group.lastname}}
  </div>
</div>

{{group.key}}
{{group.lastname}
以下是演示:

这是我能想到的最好的解决办法。它总共还有两个循环,但其中至少有一个没有使用
*ngFor

您有一个
字典
数组
s(作为数据结构),因此对于必要的迭代,您有以下时间复杂性:

  • O(n)
    n
    代表字典的长度
  • O(m)
    m
    表示值的长度(类型
    数组
执行迭代的任何地方的总复杂度都是
O(mn)
O(m*n)
。例如,以下代码具有相同的时间复杂性:

Object.entries(this.dataObject).reduce((result, entry) => {
    const [key, value] = entry;
    value.forEach((v, i) => (result[`${key}_${i}`] = v.name));
    return result;
},{});
如果您有一个限制,我认为您可以借助语言方法和一些方便的技巧,如贝娄,降低时间复杂性:

Object.values(this.dataObject).map(m => m).flat().map(m => m.name);
然后,将每个项目拆分为3项:

<div *ngFor="let item of simplified2; let i = index" [id]="findId(i)">
  {{findId(i)}} {{item}}
</div>


findId(index: number) {
    return Math.floor(index / 3); //if you are sure about the length of values
}

{{findId(i)}{{{item}}
findId(索引:编号){
返回Math.floor(index/3);//如果确定值的长度
}

我提供了上面提到的所有内容。您可以学习有关

的更多信息。您可以生成一个新属性并使用此新属性

在您的组件中

dataObject = {
    A: [
        {id: 1, name: 'Mike', lastname: 'asmith'},
        {id: 2, name: 'Mary', lastname: 'alters'},
        {id: 3, name: 'Boris', lastname: 'al'}
    ],
    B: [
        {id: 1, name: 'Lauren', lastname: 'bmith'},
        {id: 2, name: 'Travis', lastname: 'balters'},
        {id: 3, name: 'Barn', lastname: 'bl'}
    ], 
    ...
}
dataObjectDisp = Object.entries(this.dataObject).reduce((prev, [key, value]) =>{
  return [...prev, ...value.map((user, index) => ({ 
    ...user, parent: key, index }))]
}, [])
上述代码将结构简化为

[
{
“id”:1,
“姓名”:“迈克”,
“lastname”:“asmith”,
“家长”:“A”,
“索引”:0
},
{
“id”:2,
“姓名”:“玛丽”,
“lastname”:“alters”,
“家长”:“A”,
“索引”:1
},
...
]
现在我们有了一种方法来确定新部分何时开始。其指数将为零

要显示html,您可以执行以下操作

新建
{{item.parent}}
{{item.lastname}

注意属性
[attr.data article]='“section”+item.parent'
。这可用于识别不同的部分

如何为每个部分添加id为的div?例如,对于“A”部分及其用户,您将如何使用id=“section-A”将其包装在一个部分中,对于“B”部分,您将如何使用id=“section-B”将其包装在一个div中,等等?@progx您无法使用我的解决方案为整个组分配一个div id,因为它的设计是在数据集的扁平版本中循环。但是,您可以使用解决方案设置所需的div id。示例:使用我的解决方案?你的意思是重新使用2*NGF指令吗?我只想用一个*ngFor.@progx我回答了你的问题,而不是你的评论。当涉及到第二个问题时,您基本上创建了一个1深度的div循环,如:section-a-1、section-a-2、section-a-3、section-b-1。。。。您不能对它们进行分组并使用组ID包装它们,因为没有父div。如果您想这样做,请保留代码并使用更改第一个div。我希望输出与我的相同(标题-例如“a”及其子元素下方),然后我希望为每个节添加div ID,例如,对于a节,“section-b”,添加“section-a”对于“B”部分,依此类推。您知道如何做到这一点吗?@progx正如我前面所述,您最终将拥有与您自己的代码相同的时间复杂性,以满足您的目标,即
O(nm)
,以及基于必要迭代的性能问题。我想到的唯一方法是使用分页技术来控制性能并按需加载所需的部件。@progx您想要的是计算机算法之外的东西!您知道您的解决方案的时间复杂度是多少吗?OP有性能问题。@Owen Kelvin您能提供一个像stackblitz这样的实时演示吗?我想用id将所有部分包装在一个div中。例如,对于部分a,我想添加一个id=“sectionA”,它的所有子元素都应该在里面。您的解决方案向每个子项(每个人)添加一个“”节a。希望这能让你sense@OwenKelvin我一直在尝试使用单*ngFor,而您的新解决方案使用双*ngFor。然而,我非常感谢你的工作和努力,所以我给你额外的100点声誉积分。谢谢你,伙计!
<div *ngFor="let item of simplified2; let i = index" [id]="findId(i)">
  {{findId(i)}} {{item}}
</div>


findId(index: number) {
    return Math.floor(index / 3); //if you are sure about the length of values
}
dataObject = {
    A: [
        {id: 1, name: 'Mike', lastname: 'asmith'},
        {id: 2, name: 'Mary', lastname: 'alters'},
        {id: 3, name: 'Boris', lastname: 'al'}
    ],
    B: [
        {id: 1, name: 'Lauren', lastname: 'bmith'},
        {id: 2, name: 'Travis', lastname: 'balters'},
        {id: 3, name: 'Barn', lastname: 'bl'}
    ], 
    ...
}
dataObjectDisp = Object.entries(this.dataObject).reduce((prev, [key, value]) =>{
  return [...prev, ...value.map((user, index) => ({ 
    ...user, parent: key, index }))]
}, [])