【问题标题】:Filter and clone object properties过滤和克隆对象属性
【发布时间】:2017-04-26 06:29:47
【问题描述】:

我有 2 个对象数组:itemsList 和 itemsFetched。每个数组中的所有对象都具有相同的结构(nr 个键/值)。其中一个键具有相同的“含义”,但名称不同(itemsList 上的 item_id,itemsFetched 上的 id )。它们的值是相同的。

我需要过滤 itemsList 数组,只留下 item_id 值等于 上 id 值的对象itemsFetched。然后将 itemsFetched 数组(与 item_id=id 匹配)上每个对象的键/值 count 复制(添加)到过滤后的数组。

我有一个工作代码,但我确信这不是解决这个问题的最佳方法。我之前已经问过类似的问题(关于“过滤器”部分)解决了我的问题,但由于我必须在过滤后添加“计数”部分,我最终重构了整个事情。

itemsList(示例)

[
  {
      "id": 0,
      "name": "Egg",
      "img": "http://www.serebii.net/pokemongo/items/egg.png"
  },
  {
      "id": 1,
      "name": "Pokeball",
      "img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
  },
  {
      "id": 2,
      "name": "Greatball",
      "img": "http://www.serebii.net/pokemongo/items/greatball.png"
  },
  { 
      "id": 401,
      "name": "Incense",
      "img": "http://www.serebii.net/pokemongo/items/incense.png" 
  },
  { 
      "id": 901,
      "name": "Incubator (Unlimited)",
      "img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
  }
]

itemsFetched(示例)

[ 
  {
    "item_id": 1, 
    "count": 50,
    "unseen": true
  },
  {
    "item_id": 401,
    "count": 2, 
    "unseen": true
  },
  { 
    "item_id": 901, 
    "count": 1, 
    "unseen": true 
  }
]

resultArray(到底想要什么)

[
  { 
    "id": 1,
    "name": "Pokeball",
    "count": 50,
    "img": "http://www.serebii.net/pokemongo/items/20pokeballs.png",
  },
  { 
    "id": 401,
    "name": "Incense",
    "count": 2,
    "img": "http://www.serebii.net/pokemongo/items/incense.png"
  },
  { 
    "id": 901,
    "name": "Incubator (Unlimited)",
    "count": 1,
    "img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
  }
]

我当前的代码(工作)

let arr = [];
itemsFetched.forEach((item) => {
  itemsList.forEach((item2) => {
    if (item.item_id === item2.id) {
      arr.push({
        "id": item.item_id,
        "name": item2.name,
        "count": item.count,
        "img": item2.img
      });
    }
  });
});

PS:我能够使用 ES6/7 语法/功能。

【问题讨论】:

  • 最好在服务器上做这个处理。始终将格式化的数据返回给浏览器。这样您就不必在需要这些数据的每个页面上执行相同的数据操作了。
  • 是的,我知道这一点。这是在服务器端完成的。其中一个数组位于 json 文件及其模板类型上,另一个是对外部 api 调用的响应。
  • 他尝试从数组中获取 id。这里--->> if (itemsFetched.item_id === itemsList.id)
  • 为什么会有这么多垃圾邮件?我已经告诉过你,这不是问题。那是一个复制粘贴编辑错误。这里的问题是关于效率、最佳实践和 ES6/7 语法/特性的使用。大多数人似乎都明白这一点,除了你。
  • @nip 在这种情况下,kcats 有最好的答案。通过将数组转换为哈希集可以防止低效的嵌套循环。

标签: javascript arrays node.js object


【解决方案1】:

你可以使用hash map来复杂地减少时间,你的算法是O(m*n),下面是O(m+n+r)

const itemsMap = itemsList.reduce((map, item) => {
    map[item.id] = item
    return map
}, {})
const results = itemsFetched
    .filter((item) => itemsMap.hasOwnProperty(item.item_id))
    .map((item) => ({
        id: item.item_id,
        name: itemsMap[item.item_id].name,
        count: item.count,
        img: itemsMap[item.item_id].img,
    }))

【讨论】:

  • 感谢您的意见。我会测试一下,看看效果如何。 (另外,控制台日志记录无处不在,以了解发生了什么嗯)
【解决方案2】:

将for ... of 循环(ES6 功能)与Array#map 结合使用。

这使您在第一次找到匹配项时更容易return 合并对象,这是一种逻辑优化,因为两个列表都不应包含多个具有给定id 的条目。

const result = itemsFetched.map(data => {
  for (let item of itemsList) {
    if (data.item_id === item.id) {
      return {
        id: item.id,
        name: item.name,
        count: data.count,
        img: item.img
      }
    }
  }
})

片段:

const itemsList = [{
  "id": 0,
  "name": "Egg",
  "img": "http://www.serebii.net/pokemongo/items/egg.png"
}, {
  "id": 1,
  "name": "Pokeball",
  "img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
}, {
  "id": 2,
  "name": "Greatball",
  "img": "http://www.serebii.net/pokemongo/items/greatball.png"
}, {
  "id": 401,
  "name": "Incense",
  "img": "http://www.serebii.net/pokemongo/items/incense.png"
}, {
  "id": 901,
  "name": "Incubator (Unlimited)",
  "img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
}]

const itemsFetched = [{
  "item_id": 1,
  "count": 50,
  "unseen": true
}, {
  "item_id": 401,
  "count": 2,
  "unseen": true
}, {
  "item_id": 901,
  "count": 1,
  "unseen": true
}]


const result = itemsFetched.map(data => {
  for (let item of itemsList) {
    if (data.item_id === item.id) {
      return {
        id: item.id,
        name: item.name,
        count: data.count,
        img: item.img
      }
    }
  }
})

console.log(result)

【讨论】:

  • 首先,感谢您的意见。我已经开始查看 .map 但我不知道...的。我会看看那个。此外,如果这是一个“大小合理的 webapp”,这些更改将提高服务器的性能,特别是 for ... 部分,因为它在找到匹配项后会中断?假设是,那会很明显吗?还是只是一个小细节?
  • 列表越长,性能差异就越重要。由于这是一个快速修复,我宁愿在找到匹配项时立即return。
  • 知道了。刚刚实施了你的建议,它正在工作。谢谢!
【解决方案3】:

一种改进方法是使用for..of 语句而不是forEach 用于内部循环。一旦 id 匹配,这有助于打破循环。没有直接的方法可以脱离 forEach 方法。

let arr = [];
itemsFetched.forEach((item) => {
  for (let item2 of itemsList) {
    if (itemsFetched.item_id === itemsList.id) {
      arr.push({
        "id": itemsFetched.item_id,
        "name": itemsList.name,
        "count": itemsFetched.count,
        "img": itemsList.img
      });
      break;
    }
  }
});

【讨论】:

【解决方案4】:

像这样?

var itemsList = [
  {
      "id": 0,
      "name": "Egg",
      "img": "http://www.serebii.net/pokemongo/items/egg.png"
  },
  {
      "id": 1,
      "name": "Pokeball",
      "img": "http://www.serebii.net/pokemongo/items/20pokeballs.png"
  },
  {
      "id": 2,
      "name": "Greatball",
      "img": "http://www.serebii.net/pokemongo/items/greatball.png"
  },
  { 
      "id": 401,
      "name": "Incense",
      "img": "http://www.serebii.net/pokemongo/items/incense.png" 
  },
  { 
      "id": 901,
      "name": "Incubator (Unlimited)",
      "img": "http://www.serebii.net/pokemongo/items/eggincubator.png"
  }
];

var itemsFetched = [ 
  {
    "item_id": 1, 
    "count": 50,
    "unseen": true
  },
  {
    "item_id": 401,
    "count": 2, 
    "unseen": true
  },
  { 
    "item_id": 901, 
    "count": 1, 
    "unseen": true 
  }
]



let arr = [];
itemsFetched.forEach((item) => {
  itemsList.forEach((item2) => {
    if (item.item_id == item2.id) {
      arr.push({
        "id": item.item_id,
        "name": item2.name,
        "count": item.count,
        "img": item2.img
      });
    }
  });
});

console.log(arr);

【讨论】:

  • 如何更好?
  • 什么??我的代码正在运行。我只是想知道是否有更好的方法来做到这一点,而不是 2 个嵌套的 for-each + if + push。 (也许我应该补充一下,我仍在学习 ES6/7 特性/语法,以及与数组相关的函数,如 .filter、.map、.includes)
  • 抱歉,您的代码不适用于此:if (itemsFetched.item_id === itemsList.id) 因为您尝试从数组中获取 id -_-
  • 它有效。我只是没有粘贴完整的代码,因为我认为大多数人都理解(正如您在其他答案中看到的那样)
  • 我明白你的意思。我编辑了代码以使其更容易理解并在这部分搞砸了
猜你喜欢
  • 2016-08-05
  • 2015-02-08
  • 2015-02-04
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2018-08-08
相关资源
最近更新 更多