循环遍历对象数组,并根据特定条件生成新数组

时间:2016-08-25 22:52:29

标签: javascript arrays loops ecmascript-6

我有一个看起来像这样的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次,我只需要它一次并且在他所有照片的数组中。我该怎么做?我应该使用什么类型的循环?感谢...

4 个答案:

答案 0 :(得分:2)

这是另一个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内部。它将作为下一次迭代的第一个参数传递,等等。

  4. reduce返回最终累积的对象,即Map。由于这不是所需的输出格式,因此将其转换为数组,通过取values(我们不再需要键),并将其转换为{{3 ([... ])。

答案 1 :(得分:1)

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

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]});

答案 2 :(得分:1)

使用ES6并使用数据副本创建新对象,从而保留原始数据。

  1. 创建临时地图。
  2. 循环对象中的每个条目。
  3. 如果地图中不存在条目ID,则创建并设置一个 正确格式的条目副本。
  4. 如果条目已存在,则只需将照片副本推送到条目。
  5. 从地图返回一个数组。
  6. 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 :(得分:1)

解决方案是

  • 将每个用户转换为新用户(带有一系列照片)
  • 按用户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;
});