JS 如何遍历数组对象实现分组添加属性?

例如:

list: [
    {id: 1, title: "党委组织部", desc: ""},
    {id: 2, title: "财务部", desc: ""},
    {id: 3, title: "党委组织部", desc: ""},
    {id: 4, title: "党委组织部", desc: ""},
    {id: 5, title: "人事部", desc: ""},
    {id: 6, title: "人事部", desc: ""},
    {id: 7, title: "人事部", desc: ""}
]

遍历数组里所有的对象元素, 根据某个对象属性,例如:title, 如果title的属性值都相同的话,则给数组里属性值相同的第一个对象元素添加isShow:true属性,其他添加为isShow:false

转换结果如下:

list: [
    {id: 1, title: "党委组织部", desc: "", isShow: true},
    {id: 2, title: "财务部", desc: "", isShow: true},
    {id: 3, title: "党委组织部", desc: "", isShow: false},
    {id: 4, title: "党委组织部", desc: "", isShow: false},
    {id: 5, title: "人事部", desc: "", isShow: true},
    {id: 6, title: "人事部", desc: "", isShow: false},
    {id: 7, title: "人事部", desc: "", isShow: false},
    {id: 8, title: "财务部", desc: "", isShow: false}
]
阅读 3.9k
8 个回答

要说方法,有很多

1. 分组。

按 title 分组,然后对每组第一个项设置 isShow: true,其他的设置 isShow: false

分组方法可以自己写,但是不如用 Lodash 来得简单。何况,如果自己写的话,不如用下面(第 2 种)方法。

想自己实现分组可参阅:JavaScript 数组分组的实现
_(list).groupBy("title")
    .values()
    .forEach(list => {
        list[0].isShow = true;
        _.drop(list, 1).forEach(it => it.isShow = false);
    });

不过说实在的,这种方法并不优。处理过程中分组需要遍历一次,赋值还需要再进行多次小遍历。

遍历并记录

用一个集合(通常是 Set)来记录已经处理过的 title。然后在遍历的过程中,检查集合中存在,则 isShow: false;不存在则 isShow: true 同时把 title 加入集合。

这个方法就如 @roger 描述的那样,@llfididi 实现了代码。我这个代码略有不同,是直接修改的原对象,添加属性。

list.reduce((set, it) => {
    it.isShow = !set.has(it.title);
    if (it.isShow) {
        set.add(it.title);
    }
    return set;
}, new Set());

其中 Set 对象也可以用普通 JS 对象代替,用 title in set 来判断是否存在,代码略。

这种方法处理只需要一次遍历,但需要一个 title 集合缓存。

查找

先把所有 title 找出来,去重。然后遍历数据集,全部设置为 false,再遍历 title 集合,在数据售中找到每一个 title 的第 1 项,设置为 true。

@hfhan 利用了每次查找相同 title 都会得到同一个 index 的特性来处理。但每次查询都是对源数据的一次不完全遍历,而且查询次数比较多(数据项数)

list.forEach(it => it.isShow = false);
const set = new Set(list.map(it => it.title));
[...set].forEach(s => list.find(({ title }) => title == s).isShow = true);
console.log(list);

这个代码会遍历 title 数量次非完全遍历 + 2 次全遍历(生成 title 集合也算)。其中两次全遍历是可以合并的。

let newList=list.reduce((acc,item)=>{
  let find=acc.find((c)=>c.title==item.title)
  item.isShow=find?false:true;
  return [...acc,item]
},[])

findIndex版本

list.forEach((item, index) => item.isShow = index === list.findIndex(citem => citem.title === item.title))

1:构建额外对象或者map保存状态(时间复杂度On,需要额外空间)
2:遍历数组的每一项

1:取对象中对应title的值不为true就将该值改为true,并把当前项isshow改为true,为true就跳过
  const list = [
    { id: 1, title: "党委组织部", desc: "" },
    { id: 2, title: "财务部", desc: "" },
    { id: 3, title: "党委组织部", desc: "" },
    { id: 4, title: "党委组织部", desc: "" },
    { id: 5, title: "人事部", desc: "" },
    { id: 6, title: "人事部", desc: "" },
    { id: 7, title: "人事部", desc: "" },
  ];

  const set = new Set();
  const newList = list.map((e) => {
    const { title } = e;
    const newData = { ...e, isShow: !set.has(title) };
    set.add(title);
    return newData;
  });
  console.log(newList);
  let list = [
    { id: 1, title: "党委组织部", desc: "" },
    { id: 2, title: "财务部", desc: "" },
    { id: 3, title: "党委组织部", desc: "" },
    { id: 4, title: "党委组织部", desc: "" },
    { id: 5, title: "人事部", desc: "" },
    { id: 6, title: "人事部", desc: "" },
    { id: 7, title: "人事部", desc: "" }
  ]



  for (let i = 0; i < list.length; i++) {
    let title = list[i].title
    if (list[i].isShow == undefined) {
      // 防止重复赋值, 第一次时该字段是undefined
      list[i].isShow = true
    }

    // 判断当前i后面的对象
    for (let j = i + 1; j < list.length; j++) {
      if (list[j].title === title) {
        list[j].isShow = false
      }
    }
  }

  console.log(list);

结果:

image.png

第一种方法
let arr = []
let newArr = list.map(v => ({...v, isShow: arr.includes(v.title) ? false : arr.push(v.title) && true}))
console.log(newArr)
第二种方法
let newArr = list.reduce((s, v) => s.push({...v, isShow: !s.some(it => it.title === v.title)}) && s, [])
console.log(newArr)
let map = new Map()
    let arr = [
      { id: 1, title: "党委组织部", desc: "" },
      { id: 2, title: "财务部", desc: "" },
      { id: 3, title: "党委组织部", desc: "" },
      { id: 4, title: "党委组织部", desc: "" },
      { id: 5, title: "人事部", desc: "" },
      { id: 6, title: "人事部", desc: "" },
      { id: 7, title: "人事部", desc: "" }
    ]

    arr.forEach((item, index, array) => {
      item.isShow = false
      
      if (!map.has(item.title)) {
        map.set(item.title, index)
      } else {
        array[map.get(item.title)].isShow = true
      }
    })
    
    console.log(arr);

清晰易懂

撰写回答
你尚未登录,登录后可以
  • 和开发者交流问题的细节
  • 关注并接收问题和回答的更新提醒
  • 参与内容的编辑和改进,让解决方法与时俱进
推荐问题
宣传栏