【问题标题】:Loop over array of objects, and generate new array by certain conditions循环对象数组,并根据特定条件生成新数组
【发布时间】:2017-01-02 12:21:27
【问题描述】:

我有一个如下所示的 Javascript 对象:

const obj = [
{
  name: "Ali",
  userID: 123,
  type: "photo",
  photo: {
    "title": "Me",
    "src": "/cool.jpg",
  }
},
{
  name: "Ali",
  userID: 123,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
},
{
  name: "John",
  userID: 1234,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
},
{
  name: "John",
  userID: 1234,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
}];

我需要遍历它并返回一个如下所示的数组:

const obj = [
  {
    name: "Ali",
    userID: 123,
    type: "photo",
    photos: [
      {
        title: "Me",
        src: "/cool.jpg"
      },
      {
        title: "Photo",
        src: "/photo.jpg"
      }
    ]
  },
  {
    name: "John",
    userID: 1234,
    type: "photo",
    photos: [
      {
        "title": "Me",
        "src": "photo.jpg"
      },
      {
        title: "Photo",
        src: "/photo.jpg"
      }
    ]
  }
]

请注意,第一个对象可以包含超过 100 次具有相同名称的对象,我只需要一次并且在他所有照片的数组中。我该怎么做?我应该使用什么类型的循环?谢谢...

【问题讨论】:

  • @RokoC.Buljan 我试图实现的数组与此完全不同
  • 是的……误读了。不完全但接近。您实际上想将用户的photo 合并为多个photos(可以摘自here)。你试过什么?你提出的问题表明你没有付出任何努力。您是否已经尝试过针对特定问题的任何代码?或者您正在尝试找人为您编写代码?
  • 我有一些代码,但它并没有完全符合我的要求,我需要按用户 ID 堆叠这些照片,我将添加我的代码
  • 想要一个新的数据数组,还是修改原来的obj
  • @Xotic750 对我都有好处

标签: javascript arrays loops ecmascript-6


【解决方案1】:

这是另一个 ES6 脚本:

function merge(input) {
    return [...input.reduce( (acc, {name, userID, type, photo} ) => {
        let obj = acc.get(name) || {name, userID, type, photos: []};
        obj.photos.push(photo);
        return acc.set(name, obj);
    }, new Map()).values()];
}

// Sample data
var input = [{
  name: "Ali",
  userID: 123,
  type: "photo",
  photo: {
    "title": "Me",
    "src": "/cool.jpg",
  }
},
{
  name: "Ali",
  userID: 123,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
},
{
  name: "John",
  userID: 1234,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
},
{
  name: "John",
  userID: 1234,
  type: "photo",
  photo: {
    "title": "Photo",
    "src": "/photo.jpg"
  }
}];

// convert
result = merge(input);

// output result
console.log(result);

说明:

input.reduce 迭代输入,并累积一个初始化为新 Map 的值(reduce 的第二个参数)。

在每次迭代中,累积值作为第一个参数传递,第二个参数接收输入元素。通过destructuring assignment,我们可以得到nameuserIDtypephoto 属性的变量。

每次迭代执行三个语句:

  1. obj 被定义为我们拥有的 name 值的累积对象,或者 (||) 如果我们还没有,作为给定的输入元素,但没有 photo 属性和新的photos 数组:{name, userID, type, photos: []}

  2. 当前照片已添加到其中。

  3. 生成的对象被分配回累积的 Map 对象,该对象本身返回给reduce 内部。它将作为下一次迭代的第一个参数传递,等等。

reduce 返回最终累积的对象,即 Map。由于这不是所需的输出格式,因此将其转换为数组,这是通过获取其values(我们不再需要键)并将其转换为带有spread operator(@ 987654341@).

【讨论】:

    【解决方案2】:

    使用 ES6 并使用数据副本创建一个新对象,因此原始数据保持不变。

    1. 创建一个临时地图。
    2. 循环对象中的每个条目。
    3. 如果该条目的 ID 在 Map 中不存在,则创建并设置一个 格式正确的条目副本。
    4. 如果条目已经存在,那么只需将照片的副本推送到条目。
    5. 从 Map 返回一个数组。

    function merge(obj) {
      const temp = new Map();
      for (let r of obj) {
        if (temp.has(r.userID)) {
          temp.get(r.userID).photos.push(Object.assign({}, r.photo));
        } else {
          const entry = Object.assign({}, r);
          entry.photos = [Object.assign({}, r.photo)];
          delete entry.photo;
          temp.set(r.userID, entry);
        }
      }
      return Array.from(temp, x => x[1]);
    }
    
    const obj = [{
      name: "Ali",
      userID: 123,
      type: "photo",
      photo: {
        "title": "Me",
        "src": "/cool.jpg",
      }
    }, {
      name: "Ali",
      userID: 123,
      type: "photo",
      photo: {
        "title": "Photo",
        "src": "/photo.jpg"
      }
    }, {
      name: "John",
      userID: 1234,
      type: "photo",
      photo: {
        "title": "Photo",
        "src": "/photo.jpg"
      }
    }, {
      name: "John",
      userID: 1234,
      type: "photo",
      photo: {
        "title": "Photo",
        "src": "/photo.jpg"
      }
    }];
    
    const merged = merge(obj);
    document.getElementById('out').textContent = JSON.stringify(merged, null, 2);
    console.log(merged);
    <pre id="out"></pre>

    【讨论】:

    • 这实际上以我需要它的方式工作,除了,我真的不明白它是如何工作的......介意解释一下吗?谢谢!
    • 我添加了工作原理的文字描述,有帮助吗?
    【解决方案3】:

    解决办法是

    • 将每个用户转换为新用户(带有一组照片)
    • 按用户 ID 排序
    • 根据用户 ID 合并照片

    在 ES6 中

    // Transform
    let new_users = user.map(u => {
      let o = Object.assign({}, u, {photos: [u.photo]}));
      delete o.photo;
      return o;
    });
    
    // Sort by user ID
    new_users = new_users.sort((a,b) => a.userID - b.userID);
    
    // Merge on userID
    let prev = null;
    new_user = new_user.filter(u => {
      if (prev && prev.userID === u.userID) {
        prev.photos.push(u.photos[0]);
        return false;
      }
      prev = u;
      return true;
    });
    

    【讨论】:

      【解决方案4】:

      这可以满足您的大部分需求:

      var sorted = {};
      obj.forEach(function(element){
        if(sorted[element.name]){
          sorted[element.name].photos.push(element.photo)
        }else{
          sorted[element.name] = {
            name: element.name,
            userID: element.userID,
            type: element.type,
            photos:[element.photo]
          }
        }
      });
      

      这不会创建一个数组,它会创建一个以名称作为键的对象。

      const obj = [
      {
        name: "Ali",
        userID: 123,
        type: "photo",
        photo: {
          "title": "Me",
          "src": "/cool.jpg",
        }
      },
      {
        name: "Ali",
        userID: 123,
        type: "photo",
        photo: {
          "title": "Photo",
          "src": "/photo.jpg"
        }
      },
      {
        name: "John",
        userID: 1234,
        type: "photo",
        photo: {
          "title": "Photo",
          "src": "/photo.jpg"
        }
      },
      {
        name: "John",
        userID: 1234,
        type: "photo",
        photo: {
          "title": "Photo",
          "src": "/photo.jpg"
        }
      }];
      
      var sorted = {};
      obj.forEach(function(element){
        if(sorted[element.name]){
          sorted[element.name].photos.push(element.photo)
        }else{
          sorted[element.name] = {
            name: element.name,
            userID: element.userID,
            type: element.type,
            photos:[element.photo]
          }
        }
        console.log(sorted);
      });
      
      
      var sortedarray = sorted.map()
      console.log(sortedarray);

      您可以添加这段代码将对象转换为数组:

      var sortedarray = Object.keys(sorted).map(function(person){
      return sorted[person]});
      

      【讨论】:

        猜你喜欢
        • 2023-01-13
        • 2021-03-23
        • 1970-01-01
        • 2020-01-06
        • 2020-01-28
        • 2021-02-07
        • 2021-12-22
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多