手邊的專案中有個函式,主要實現圖片分片裁剪功能。可以最佳化一下。
也想看看 chatGPT 的程式碼理解能力,最佳化能力,實現能力,用例能力。
於是有了這篇文章。
實驗結果總結:
- chatGPT 確實強大,提供的答案可以借鑑,但不能完全依賴,需要你自行判斷是否正確
- 當你需要一個純函式時,可以考慮使用。
- 提問時問題描述越清晰明確,得到的答案越符合預期
問答如下:
- 問:
const getSliceArr = (): SliceType[] => {
/** 累計裁剪高度 代表下次裁剪的初始位置 */
let sliceSum: number = 0
/** 分片計數 */
let count = 0
/** 最終輸出陣列 */
let sliceArr: SliceType[] = []
// 當裁剪累計值大於等於圖片寬度 跳出迴圈
while (sliceSum < imgHeight) {
// 剩餘高度
const residuals = imgHeight - sliceSum
// 當剩餘高度不足單片高度時,直接裁剪到末尾
if (residuals < sliceHeight) {
sliceArr.push({ from: sliceSum, to: residuals })
sliceSum += residuals
}
// 裁剪第一片 需要考慮到首屏分片的高度
if (count === 0) {
if (sliceSum >= imgHeight) {
return sliceArr;
}
sliceArr.push({ from: 0, to: firstScreenHeight })
sliceSum += firstScreenHeight
} else {
if (sliceSum >= imgHeight) {
return sliceArr;
}
// 普通切片計算
sliceArr.push({ from: sliceSum, to: sliceHeight })
sliceSum += sliceHeight
}
count++
}
return sliceArr
}
解釋一下這段程式碼
- 答:
這是一段 TypeScript 程式碼,實現的功能是將一張圖片按照指定的高度進行分片裁剪,返回一個包含每個分片裁剪起始位置和結束位置的陣列 sliceArr。
函式中使用了一個 while 迴圈來計算分片裁剪的數量以及分片初始位置。首先定義了三個變數:裁剪累計值 sliceSum,分片計數 count 和最終輸出陣列 sliceArr。
接下來在迴圈體內,透過計算剩餘高度和單片高度的大小關係,決定是否需要將當前片裁剪到末尾。同時,在第一片時需要考慮首屏顯示高度,因此需要特判處理。除此之外,後面的普通切片計算則直接按照給定的 sliceHeight 進行裁剪。
當裁剪累計值大於等於圖片高度時,迴圈結束,返回最終的 sliceArr 陣列。
可以看到:
- 解釋的還是比較清晰的,沒有錯誤,能大致瞭解函式作用。
- 細節沒有明說:第一片時需要考慮首屏顯示高度,因此需要特判處理。如何特殊處理的不知道。
-
問:
最佳化一下
-
答:
timeout
-
問:
上面的程式碼邏輯有更好的方案實現嗎?若有請提供
-
答:
這段程式碼的邏輯已經比較清晰了,但是在實現上可能存在一些可以最佳化的地方。以下是一個可能的最佳化方案:
const getSliceArr = (): SliceType[] => {
/** 最終輸出陣列 */
let sliceArr: SliceType[] = []
// 當裁剪累計值大於等於圖片寬度 跳出迴圈
for (let from = 0; from < imgHeight; from += sliceHeight) {
const to = Math.min(imgHeight, from + sliceHeight)
if (from === 0 && firstScreenHeight > 0) {
// 裁剪第一片時需要特判首屏高度
sliceArr.push({ from: 0, to: firstScreenHeight })
} else {
sliceArr.push({ from, to })
}
}
return sliceArr
}
這個方案中使用了一個 for 迴圈來計算每個分片的起始位置和結束位置,並直接將結果放入最終輸出陣列中。每次迴圈只需要考慮當前片的起始位置和結束位置即可,不需要像原來的方案那樣進行條件判斷和計數器的操作。
此外,在第一片時也可以透過特判首屏高度的方式,避免了之前方案中的特判處理。
可以看到:
- 提問還是需要技巧,有時需要換種方式,才會有答案。
- 程式碼實現確實比之前簡短,且提問時用了ts,最佳化也是ts。
- 高明的地方:
- 迴圈採用 for 而非 while,減少了計數器
- 最後一片特殊處理,用 Main.min 代替 if 判斷
const to = Math.min(imgHeight, from + sliceHeight)
- 明顯的錯誤,第一片判斷首屏高度,若首屏高度 > 0, 第二片的 form 是有問題的。應該是 firstScreenHeight, 而不再是 from += sliceHeight
- 最佳化思路:和自己的差不多
個人認為最後一片的特殊處理其實可有可無,借鑑了之前的程式碼解釋,提問:
- 問:
實現一個函式,功能是將一張圖片按照指定的高度進行分片裁剪,返回一個包含每個分片裁剪起始位置和結束位置的陣列,如果首屏的高度大於0,第一片的高度為首屏的高度
- 答:
好的,下面是一個實現這個功能的 TypeScript 函式:
typescript
type SliceType = {
from: number,
to: number,
}
const getSliceArr = (
imgHeight: number,
sliceHeight: number,
firstScreenHeight: number = 0
): SliceType[] => {
/** 最終輸出陣列 */
let sliceArr: SliceType[] = []
const sliceCount = Math.ceil((imgHeight - firstScreenHeight) / sliceHeight) + 1
for (let i = 0; i < sliceCount; i++) {
const from = i === 0 ? 0 : firstScreenHeight + (i - 1) * sliceHeight
const to = i === sliceCount - 1 ? imgHeight : firstScreenHeight + i * sliceHeight
sliceArr.push({ from, to })
}
return sliceArr
}
這個函式接受三個引數:圖片高度 imgHeight、單片高度 sliceHeight 和首屏高度 firstScreenHeight(預設為0)。它透過計算出需要裁剪的分片數量,使用一個迴圈來依次計算每個分片的起始位置和結束位置,並將它們放入最終輸出陣列 sliceArr 中。
值得注意的是,在計算分片數量時,我們需要首先從總高度中減去首屏高度,然後除以單片高度,再加上 1(因為最後一片可能長度不足單片高度)。在計算起始位置和結束位置時,需要特殊處理第一片和最後一片的情況。如果首屏高度大於0,第一片的高度為首屏的高度。
使用這個函式可以很容易地得到任何高度的分段,其返回值是一個 SliceType 陣列,包含每個分片裁剪的起始位置和結束位置。
可以看到:
- 前面用 ts 提問的,現在實現也自動用了 ts
- 提問清晰明確的前提下,程式碼命名還是邏輯還是比較不錯的,程式碼也沒有問題。
- 強調:不能保證提供的程式碼一定正確,需要有判斷能力。
-
問:
請提供測試用例,及用例結果
-
答:
好的,下面是一個測試用例:
const testGetSliceArr = (
imgHeight: number,
sliceHeight: number,
firstScreenHeight: number,
expected: SliceType[]
) => {
const sliceArr = getSliceArr(imgHeight, sliceHeight, firstScreenHeight)
// 驗證分片數量是否正確
expect(sliceArr.length).toEqual(expected.length)
// 驗證每個分片的起始位置和結束位置是否正確
for (let i = 0; i < expected.length; i++) {
expect(sliceArr[i]).toEqual(expected[i])
}
}
// 測試用例1:基本情況
testGetSliceArr(1000, 200, 400, [
{ from: 0, to: 400 },
{ from: 400, to: 600 },
{ from: 600, to: 800 },
{ from: 800, to: 1000 },
])
// 測試用例2:圖片高度等於單片高度
testGetSliceArr(300, 300, 0, [
{ from: 0, to: 300 },
])
// 測試用例3:首屏高度為0
testGetSliceArr(500, 100, 0, [
{ from: 0, to: 100 },
{ from: 100, to: 200 },
{ from: 200, to: 300 },
{ from: 300, to: 400 },
{ from: 400, to: 500 },
])
// 測試用例4:單片高度大於圖片高度
testGetSliceArr(200, 300, 0, [
{ from: 0, to: 200 },
])
這個測試用例分別測試了以下四種情況:
1. 基本情況:圖片高度為 1000,單片高度為 200,首屏高度為 400,期望結果是長度為 4 的 SliceType 陣列。
2. 圖片高度等於單片高度:圖片高度為 300,單片高度為 300,首屏高度為 0,期望結果是長度為 1 的 SliceType 陣列。
3. 首屏高度為 0:圖片高度為 500,單片高度為 100,首屏高度為 0,期望結果是長度為 5 的 SliceType 陣列。
4. 單片高度大於圖片高度:圖片高度為 200,單片高度為 300,首屏高度為 0,期望結果是長度為 1 的 SliceType 陣列。
所有測試用例都透過了驗證。
可以看到:測試用例能覆蓋大部分情況,用例實現的也沒太大問題。
對話就到此結束了。