英文:
Merging objects in array- javascript
问题
I know there are many variants of this question on here, the answers of which I utilized in getting to this step, but I'm not getting the expected result and I'm not sure why.
I started with some dummy data- an array of objects, each containing an ISO date value for a key- date. I had to remove undefined values and then wanted to merge the results based on that date value. The resulting data before the merge looks like this:
[{
"data": {
"hours": ["2"],
"timeIn": ["2023-05-01T18:00:00Z"],
"timeOut": ["2023-05-01T20:00:00Z"],
"type": ["Client"]
},
"date": "5/1/2023",
"entries": 2
}, {
"data": {
"hours": [2, 2],
"timeIn": ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],
"timeOut": ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],
"type": ["Client"]
},
"date": "5/10/2023",
"entries": 4
}, {
"date": "5/1/2023",
"visits": 2
}, {
"date": "5/10/2023",
"visits": 4
}, {
"date": "5/1/2023",
"miles": 20
}, {
"date": "5/10/2023",
"miles": 40
}]
And based on this answer: https://stackoverflow.com/a/43742999/14330332
I copied it largely straight over:
var merged = [];
cleaned.forEach(function(item) {
var idx;
var found = merged.some(function(el, i) {
idx = el.date === item.date ? i : null;
return el.date === item.date;
});
if (!found) {
merged.push(item);
} else if (idx !== null) {
console.log(Object.keys(item))
for (k in Object.keys(item)) {
console.log(k)
if (item.hasOwnProperty(k)) {
merged[idx][k] = item[k];
}
}
}
});
But for some reason the objects containing 'visits' and 'miles' props are not being included in the final output:
[{
"data": {
"hours": ["2"],
"timeIn": ["2023-05-01T18:00:00Z"],
"timeOut": ["2023-05-01T20:00:00Z"],
"type": ["Client"]
},
"date": "5/1/2023",
"entries": 2
}, {
"data": {
"hours": [2, 2],
"timeIn": ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],
"timeOut": ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],
"type": ["Client"]
},
"date": "5/10/2023",
"entries": 4
}]
With the use of hasOwnProperty in the for loop, why would those not be included as well? Being that the idx (date prop) is found and != null, the prop is distinct and should get added to the merge, no? Been staring at this too long now and just not sure what I'm missing.
Heres a link to a jsFiddle I'm playing around in:
https://jsfiddle.net/joznox/hyeb2qj4/65/
英文:
I know there are many variants of this question on here, the answers of which I utilized in getting to this step, but I'm not getting the expected result and I'm not sure why.
I started with some dummy data- an array of objects, each containing an ISO date value for a key- date. I had to remove undefined values and then wanted to merge the results based on that date value. The resulting data before the merge looks like this:
[{
data: {
hours: ["2"],
timeIn: ["2023-05-01T18:00:00Z"],
timeOut: ["2023-05-01T20:00:00Z"],
type: ["Client"]
},
date: "5/1/2023",
entries: 2
}, {
data: {
hours: [2, 2],
timeIn: ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],
timeOut: ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],
type: ["Client"]
},
date: "5/10/2023",
entries: 4
}, {
date: "5/1/2023",
visits: 2
}, {
date: "5/10/2023",
visits: 4
}, {
date: "5/1/2023",
miles: 20
}, {
date: "5/10/2023",
miles: 40
}]
And based on this answer: https://stackoverflow.com/a/43742999/14330332
I copied it largely straight over:
var merged = [];
cleaned.forEach(function(item) {
var idx;
var found = merged.some(function(el, i) {
idx = el.date === item.date ? i : null;
return el.date === item.date;
});
if (!found) {
merged.push(item);
} else if (idx !== null) {
console.log(Object.keys(item))
for (k in Object.keys(item)) {
console.log(k)
if (item.hasOwnProperty(k)) {
merged[idx][k] = item[k];
}
}
}
});
But for some reason the objects containing 'visits' and 'miles' props are not being included in the final output:
[{
data: {
hours: ["2"],
timeIn: ["2023-05-01T18:00:00Z"],
timeOut: ["2023-05-01T20:00:00Z"],
type: ["Client"]
},
date: "5/1/2023",
entries: 2
}, {
data: {
hours: [2, 2],
timeIn: ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],
timeOut: ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],
type: ["Client"]
},
date: "5/10/2023",
entries: 4
}]
With the use of hasOwnProperty in the for loop, why would those not be included as well? Being that the idx (date prop) is found and != null, the prop is distinct and should get added to the merge, no? Been staring at this too long now and just not sure what I'm missing.
Heres a link to a jsFiddle I'm playing around in:
https://jsfiddle.net/joznox/hyeb2qj4/65/
答案1
得分: 1
以下是翻译好的部分:
问题出在这一行:
for (k in Object.keys(item))
这里的 k
将会获取由 Object.keys
返回的数组中的索引值,即 0、1、2、... 这些不是 item
中的属性,所以下一个 if
条件将会为假,没有任何内容被添加到合并的对象中。
虽然不是问题,但是 k
应该使用 let
或 const
定义,现在它被隐式定义为全局变量。
为了纠正这个问题,使用 for..of
:
for (let k of Object.keys(item))
请注意,不需要测试 hasOwnProperty
,因为 Object.keys
仅迭代满足此条件的属性。
替代代码
虽然不是您的问题,但值得创建一个以日期为键的映射,并将相应的合并对象关联到它。最初,该对象将为空,但然后您可以再次迭代数据,将项目合并到映射中按日期为键的对象中。
其次,您可以使用 Object.assign
来执行合并:
const cleaned = [{data: {hours: ["2"],timeIn: ["2023-05-01T18:00:00Z"],timeOut: ["2023-05-01T20:00:00Z"],type: ["Client"]},date: "5/1/2023",entries: 2}, {data: {hours: [2, 2],timeIn: ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],timeOut: ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],type: ["Client"]},date: "5/10/2023",entries: 4}, {date: "5/1/2023",visits: 2}, {date: "5/10/2023",visits: 4}, {date: "5/1/2023",miles: 20}, {date: "5/10/2023",miles: 40}];
const map = new Map(cleaned.map(item => [item.date, {}]));
for (const item of cleaned) Object.assign(map.get(item.date), item);
const merged = [...map.values()];
console.log(merged);
这是您提供的代码的翻译部分。
英文:
The problem is in this line:
for (k in Object.keys(item))
Here k
will get values of indices in the array that is returned by Object.keys
, so 0, 1, 2, ... These are not properties in item
, so the next if
condition will be false, and nothing gets added to the merged object.
Not the problem, but k
should be defined with let
or const
-- now it is implicitly defined as a global.
To correct this, use for..of
:
for (let k of Object.keys(item))
Note that it is not needed to test hasOwnProperty
, as Object.keys
only iterates properties for which this condition is true.
Alternative code
Not your question, but it may be worth to create a map keyed by date and associate the corresponding merged object to it. Initially that object will be empty, but then you can iterate the data again to merge items into the objects that are keyed by date in the map.
Secondly, you can benefit from Object.assign
to perform a merge:
<!-- begin snippet: js hide: false console: true babel: false -->
<!-- language: lang-js -->
const cleaned = [{data: {hours: ["2"],timeIn: ["2023-05-01T18:00:00Z"],timeOut: ["2023-05-01T20:00:00Z"],type: ["Client"]},date: "5/1/2023",entries: 2}, {data: {hours: [2, 2],timeIn: ["2023-05-10T18:00:00Z", "2023-05-10T16:00:00Z"],timeOut: ["2023-05-10T20:00:00Z", "2023-05-10T18:00:00Z"],type: ["Client"]},date: "5/10/2023",entries: 4}, {date: "5/1/2023",visits: 2}, {date: "5/10/2023",visits: 4}, {date: "5/1/2023",miles: 20}, {date: "5/10/2023",miles: 40}];
const map = new Map(cleaned.map(item => [item.date, {}]));
for (const item of cleaned) Object.assign(map.get(item.date), item);
const merged = [...map.values()];
console.log(merged);
<!-- end snippet -->
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论