JavaScript陣列物件屬性合併

前言

昨天有一位大大丟了一個 JavaScript 問題和我一起討論,他提供了一個陣列物件給我研究看看,沒想到看似這麼簡單的東西做起來這麼麻煩,還因此耗了我大概 3~4 小時左右的時間,功力果然不夠阿~

題目

1
2
3
4
5
6
const data = [
{id: 1, content: 'hello', category:'HTML5'},
{id: 1, content: 'hello', category:'JS'},
{id: 1, content: 'hello', category:'css'},
{id: 2, content: 'hi', category:'JS'},
]

要將相同 id 底下的 category 做資料處理變成以下這樣。

1
2
3
4
const data = [
{id: 1, content: 'hello', category:'HTML5,JS,CSS'},
{id: 2, content: 'hi', category:'JS'},
]

思考

一開始我第一直覺想到 join(),但是印象JavaScript中的 join() 與我想像的不一樣,所以上網查了一下JS 合併陣列方法。

MDN中有一個範例使用 concat() 可以合併多個陣列

1
2
3
4
5
var array1 = ['a', 'b', 'c'];
var array2 = ['d', 'e', 'f'];

console.log(array1.concat(array2));
// expected output: Array ["a", "b", "c", "d", "e", "f"]

參考

但是我看了一下覺得還是不對,因為陣列中包的是物件,所以思考一下要處理物件的方式勢必要使用到迴圈,所以又上網查了一下相關資料是否有人提供可以參考,好在查到了有人有類似的問題。

參考來源

所以依照別人提供的方式作為一個參考作了以下方式,過程為了做出這個我一度還搞不清楚狀況再 else 中又寫了一次for(let i in data),導致多花了許多時間。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
const data = [
{id: 1, content: 'hello', category:'HTML5'},
{id: 1, content: 'hello', category:'JS'},
{id: 1, content: 'hello', category:'css'},
{id: 2, content: 'hi', category:'JS'},
]

const cacheData = [];
const newData = [];
data.forEach((item) => {
const str = item.id;
if (typeof cacheData[str] === 'undefined') {
cacheData[str] = item;
} else {
for (const i in data) {
cacheData[str].category += `,${item.category}`;
}
}
});
console.log(cacheData);

結果答案不對,所以又花了一段時間研究。

後來自己試著將問題再好好花一點時間思考後才想到 for in 主要是針對物件來做處理,而本身我已經 forEach 處理陣列物件了,為什麼還需要再 for in 一次呢?,就把 for in 給去除修改成了以下。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
const data = [
{id: 1, content: 'hello', category:'HTML5'},
{id: 1, content: 'hello', category:'JS'},
{id: 1, content: 'hello', category:'css'},
{id: 2, content: 'hi', category:'JS'},
]

const cacheData = [];
data.forEach((item) => {
const str = item.id;
if (typeof cacheData[str] === 'undefined') {
cacheData[str] = item;
} else {
cacheData[str].category += `,${item.category}`;
}
});
console.log(cacheData);

結果就出來了。

但是這邊出現一個很神奇的事情,竟然第一筆資料是一個 empty,一時之間也想不透到底原因為何,所以自己就改用另外一種方式來做處理。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
const data = [
{id: 1, content: 'hello', category:'HTML5'},
{id: 1, content: 'hello', category:'JS'},
{id: 1, content: 'hello', category:'css'},
{id: 2, content: 'hi', category:'JS'},
]

const cacheData = [];
const newData = [];
data.forEach((item) => {
const str = item.id;
if (typeof cacheData[str] === 'undefined') {
cacheData[str] = item;
} else {
cacheData[str].category += `,${item.category}`;
}
});
// 此時會發現有一個empty
console.log(cacheData);
// 將empty處理掉再重新上傳到新陣列。
cacheData.splice(0,1)
newData.push(cacheData);
// 結果
console.log(newData);

這次答案就正常一點了…

但是因為這種處理方式感覺很不 OK,因為所以在那邊查來查去…結果原本提問的大大就跟我說問題出在這裡 let str = item.id;

因為第一筆陣列是 00 沒有任何資料所以才會導致出現 empty,所以我在一次做了修改,這次就比較剪短一點。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
const data = [
{id: 1, content: 'hello', category:'HTML5'},
{id: 1, content: 'hello', category:'JS'},
{id: 1, content: 'hello', category:'css'},
{id: 2, content: 'hi', category:'JS'},
]

const cacheData = [];
data.forEach((item) => {
// 避免陣列第0筆一開始就上傳,所以預設就-1
const str = item.id - 1;
if (typeof cacheData[str] === 'undefined') {
cacheData[str] = item;
} else {
cacheData[str].category += `,${item.category}`;
}
});
console.log(cacheData);

那麼這一次答案就完全正常了,也不用另外使用 splice 甚至宣告新陣列上傳。

結語

基本上我在遇到問題的時候,會先思考一下有哪些方式可以用,然後將我思考的東西試著丟上 Google 來搜尋試著找看看有沒有相關問題。

當我找到這邊 參考文章 時,我研究一下裡面各種寫法,然後挑一個自己最看得懂的寫法試著刻一遍…

這次真的要反省一下只看而不思考,自己也要認真想一下人家針對的問題回答所寫的程式碼才對QQ

最後附上與我互相討論的大大部落格連結,裡面他也有思考出來的答案結果。

0%