2025年1月12日 星期日

更換紗窗

 

今年第一次挑戰自己動手更換紗窗。回想兩年前,曾經請人更換3樓的紗窗,當時花費約1500-2000元左右。這次因為老婆大人在IG上看到有人到小北百貨買DIY工具自行更換紗窗,便提議我試試看,於是我也決定親自動手操作。


這次總共更換了頂樓曬衣場的3個紗窗。1月5日先更換了第一片,花費約1小時完成。到了1月11日,再接著更換另外兩片,經驗累積後,速度進步到每片約30分鐘。


第一片紗窗更換時,使用的是4.5mm壓條。本來剪了一小段舊壓條到賣場比對,但可能因舊壓條已經受擠壓縮小,導致尺寸判斷錯誤。當時滾紗窗的過程非常順利,但裝好後感覺紗窗稍微鬆動,似乎不夠緊實。後來,為了更穩固,我另外購入了5.5mm壓條。這次壓條非常緊實,甚至因為滾壓力度過大,還把紗窗滾到有些缺角。不過,相較於第一片,後來的兩片更換得更加牢固,整體完成度也提升許多。


這次DIY的過程,雖然一開始有些手忙腳亂,但在經驗中學習,越做越熟練,最終也完成了一項看似不容易的挑戰!



工具:剪刀、美工刀、一字起子(可以不用)、滾輪(小北)、4.5nm壓條(小北)、5.5nm壓條(小北)、長尾夾(固定邊框)

紗窗:防霾紗窗(小北)







更換工具

換好的紗窗

裝上後

防霾紗窗

防霾紗窗






更換浴室通風扇

 

上週(1/2),小孩浴室的通風扇壞了,讓我聯想到之前主臥的通風扇也曾壞掉並更換過。因為有過一次經驗,這次更換速度比上次(2021/11)快了許多,也更加熟練。


在挑選過程中,我查了一些其他品牌,但最後還是選擇了建商原本使用的品牌,猜想價格會比較實惠。第一次購買時印象中約花了1000元,而這次在蝦皮一次買了兩台,平均每台約850元。以主臥更換後使用10年的壽命來看,這樣的價格相當划算。


舊的通風扇拆下後,我簡單清理了一下,打算試試用潤滑油處理,看看是否能解決問題,或許還能繼續使用,延長它的使用壽命。


  • 品牌(KNS康乃馨 ES-100)
  • 使用工具電動起子(十字、一字),一字用在電線接頭(舊的接法鬆開)




更換前內部已經有點髒


 

更換前先確認接的方式


更換後


2024年6月8日 星期六

用GPT修改M語法_以日期列處理

在2023年GPT開始使用時我就詢問過GPT,可能當時的GPT還不夠聰明,給予的答案無法運行,我認為原始的語法應該可以更聰明點,詢問過Power BI社群的人,但沒有人提供答案,終於在現在再度詢問GPT給予的答案與我思考的方向依樣,只是我懂得語法不多,透過GPT幫忙解答,我也學到了新知識。





下面是GPT提供目前最優的版本

let

    // 定义日期和参数

    起始日期 = "2023/12/29",

    最新日期 = "2024/6/7",

    周前日期 = "2024/5/31",

    日期列表 = {"2023/12/29", "2024/5/10", "2024/5/17", "2024/5/24", "2024/5/31", "2024/6/7"},

    趴數 = 0.05, // 例如5%

 

    // 数据处理

    來源 = Table.NestedJoin(投資組合, {"持股標的"}, 資料_5, {"標的"}, "資料_5", JoinKind.RightOuter),

    已展開資料 = Table.ExpandTableColumn(來源, "資料_5", List.Combine({{"標的"}, 日期列表})),

    已排序資料列 = Table.Sort(已展開資料, {{"持股標的", Order.Descending}}),

    已移除資料行 = Table.RemoveColumns(已排序資料列, {"持股標的"}),

    加入淨值 = Table.AddColumn(已移除資料行, "淨值", each [股數] * [匯率] * Record.Field(_, 最新日期)),

    Base_淨值總額 = List.Sum(加入淨值[淨值]),

    加入年度漲幅 = Table.AddColumn(加入淨值, "年度漲幅", each (Record.Field(_, 最新日期) - Record.Field(_, 起始日期)) / Record.Field(_, 起始日期), Percentage.Type),

    加入周漲幅 = Table.AddColumn(加入年度漲幅, "周漲幅", each (Record.Field(_, 最新日期) - Record.Field(_, 周前日期)) / Record.Field(_, 周前日期), Percentage.Type),

    加入淨值比 = Table.AddColumn(加入周漲幅, "淨值比", each [淨值] / Base_淨值總額, Percentage.Type),

    移除多餘列 = Table.RemoveColumns(加入淨值比, {"股數", "匯率", "淨值"}),

    重新排列列 = Table.ReorderColumns(移除多餘列, List.Combine({{"標的", "淨值比"}, 日期列表, {"周漲幅", "年度漲幅"}})),

    排序及篩選 = Table.SelectRows(

        Table.Sort(重新排列列, {{"淨值比", Order.Descending}, {"標的", Order.Descending}}),

        each (List.Contains(投資組合[持股標的], [標的]) or Number.Abs([周漲幅]) >= 趴數 or List.Contains(指數, [標的])) and not List.Contains(排除, [標的])

    )

in

    排序及篩選


下面是GPT提供減少手動版本

我只是將語法丟出,GPT自動提供簡易減少手動版本

let

    來源 = Table.NestedJoin(投資組合, {"持股標的"}, 資料_5, {"標的"}, "資料_5", JoinKind.RightOuter),

    #"已展開 資料_5____" = Table.ExpandTableColumn(來源, "資料_5", {"標的","2023/12/29","2024/5/10","2024/5/17", "2024/5/24","2024/5/31","2024/6/7"}),

    已排序資料列 = Table.Sort(#"已展開 資料_5____",{{"持股標的", Order.Descending}}),

    已移除資料行 = Table.RemoveColumns(已排序資料列,{"持股標的"}),

 

    // 獲取所有日期欄位名稱

    日期欄位名稱 = List.RemoveFirstN(List.RemoveItems(Table.ColumnNames(已移除資料行), {"標的", "股數", "匯率"}), 0),

    最後一欄 = List.LastN(日期欄位名稱, 1){0},

    最後第二欄 = List.LastN(日期欄位名稱, 2){0},

   

    // 計算淨值

    T淨值_______ = Table.AddColumn(已移除資料行, "淨值", each [股數]*[匯率]*Record.Field(_, 最後一欄)),

    Base_淨值總額 = List.Sum(T淨值_______[淨值]),

 

    // 計算年度漲幅和周漲幅

    T年度漲幅_____ = Table.TransformColumnTypes(

        Table.AddColumn(T淨值_______, "年度漲幅", each (Record.Field(_, 最後一欄) - Record.Field(_, "2023/12/29")) / Record.Field(_, "2023/12/29")),

        {{"年度漲幅", Percentage.Type}}

    ),

    T周漲幅_____ = Table.TransformColumnTypes(

        Table.AddColumn(T年度漲幅_____, "周漲幅", each (Record.Field(_, 最後一欄) - Record.Field(_, 最後第二欄)) / Record.Field(_, 最後第二欄)),

        {{"周漲幅", Percentage.Type}}

    ),

   

    // 計算淨值比

    T淨值比 = Table.TransformColumnTypes(

        Table.AddColumn(T周漲幅_____, "淨值比", each [淨值] / Base_淨值總額),

        {{"淨值比", Percentage.Type}}

    ),

   

    // 移除不必要的欄位

    已移除資料行1 = Table.RemoveColumns(T淨值比, {"股數", "匯率", "淨值"}),

 

    // 重新排列欄位順序

    重新排_____ = Table.ReorderColumns(已移除資料行1, {"標的", "淨值比"} & 日期欄位名稱 & {"周漲幅", "年度漲幅"}),

 

    // 排序及篩選資料

    T排序及篩選 = Table.SelectRows(

        Table.Sort(重新排_____, {{"淨值比", Order.Descending}, {"標的", Order.Descending}}),

        each (List.Contains(投資組合[持股標的], [標的]) = true or Number.Abs([周漲幅]) >= 趴數 or List.Contains(指數, [標的]) = true) and List.Contains(排除, [標的]) = false

    ),

  

in

    T排序及篩選


修改前的版本

let

    來源 = Table.NestedJoin(投資組合, {"持股標的"}, 資料_5, {"標的"}, "資料_5", JoinKind.RightOuter),

    #"已展開 資料_5____" = Table.ExpandTableColumn(來源, "資料_5", {"標的","2023/12/29","2024/5/10","2024/5/17", "2024/5/24","2024/5/31","2024/6/7"}),

    已排序資料列 = Table.Sort(#"已展開 資料_5____",{{"持股標的", Order.Descending}}),

    已移除資料行 = Table.RemoveColumns(已排序資料列,{"持股標的"}),

    T淨值_______ = Table.AddColumn(已移除資料行, "淨值", each [股數]*[匯率]*[#"2024/6/7"]), //這裡也要修改........

    Base_淨值總額 = List.Sum(T淨值_______[淨值]),

    T年度漲幅_____ = Table.TransformColumnTypes(

                 Table.AddColumn(T淨值_______, "年度漲幅", each ([#"2024/6/7"]-[#"2023/12/29"])/[#"2023/12/29"]) , //年度如果修改要去改 資料_5週那個進階查詢

                         {{"年度漲幅", Percentage.Type}}),

    T周漲幅_____ = Table.TransformColumnTypes(

                 Table.AddColumn(T年度漲幅_____, "周漲幅", each ([#"2024/6/7"]-[#"2024/5/31"])/[#"2024/5/31"]) ,  //這裡也要改

                       {{"周漲幅", Percentage.Type}}),

    T淨值比 = Table.TransformColumnTypes(Table.AddColumn(T周漲幅_____, "淨值比", each [淨值]/Base_淨值總額),{{"淨值比", Percentage.Type}}),

    已移除資料行1 = Table.RemoveColumns(T淨值比,{"股數", "匯率","淨值"}),

    重新排_____ = Table.ReorderColumns(已移除資料行1,{"標的", "淨值比","2023/12/29","2024/5/10","2024/5/17", "2024/5/24","2024/5/31","2024/6/7","周漲幅", "年度漲幅"}),

    T排序及篩選 = Table.SelectRows(

                    Table.Sort(重新排_____,{{"淨值比", Order.Descending}, {"標的", Order.Descending}}) , each (List.Contains(投資組合[持股標的],[標的])=true or Number.Abs([周漲幅])>=趴數 or List.Contains(指數,[標的])=true) and List.Contains(排除,[標的])=false   )

in

T排序及篩選

 



2024年6月2日 星期日

用VBA針對相片及影片以日期重分類

 

針對資料夾內所有子資料夾所有照片及影片檔案都移到最上層資料夾用VBA寫一個針對相片及影片的建立日、修改日、存取日判斷,以這三個日期中最小的日期依年月資料夾分類,如果該資料夾不存在就新建,當檔案名稱如果重複時就自動在檔案名稱依序給予 _+流水號


分類結果4436個影片及照片自動移到最上層資料夾,只花不到1分鐘

分類結果
分類結果

同一時間處理完畢
同一時間處理完畢



Sub OrganizePhotosAndVideosByDate()

    Dim topFolderPath As String

    Dim fso As Object

    Dim topFolder As Object

    Dim subFolder As Object

    Dim file As Object

    Dim earliestDate As Date

    Dim yearMonth As String

    Dim targetFolder As String

    Dim fileExtensions As Variant

    Dim i As Integer

    Dim fileName As String

    Dim newFileName As String

    Dim counter As Integer


    ' 設置要處理的頂層資料夾路徑

    topFolderPath = "C:\Your\Path\To\PhotosAndVideos" ' 替換為實際的路徑

    

    ' 要處理的文件副檔名

    fileExtensions = Array("jpg", "jpeg", "png", "gif", "bmp", "mp4", "avi", "mov", "wmv", "mkv")

    

    ' 創建 FileSystemObject

    Set fso = CreateObject("Scripting.FileSystemObject")

    Set topFolder = fso.GetFolder(topFolderPath)

    

    ' 遍歷頂層資料夾及其所有子資料夾中的每個檔

    Call ProcessFolder(topFolder, fso, topFolderPath, fileExtensions)

    

    MsgBox "Files have been organized by date.", vbInformation

End Sub


Sub ProcessFolder(folder As Object, fso As Object, topFolderPath As String, fileExtensions As Variant)

    Dim file As Object

    Dim subFolder As Object

    Dim earliestDate As Date

    Dim yearMonth As String

    Dim targetFolder As String

    Dim fileName As String

    Dim newFileName As String

    Dim counter As Integer


    ' 遍歷資料夾中的每個檔

    For Each file In folder.Files

        ' 檢查檔副檔名是否在目標副檔名清單中

        If IsInArray(LCase(fso.GetExtensionName(file.Path)), fileExtensions) Then

            ' 獲取檔的創建日期、修改日期和訪問日期

            earliestDate = GetEarliestDate(file.DateCreated, file.DateLastModified, file.DateLastAccessed)

            

            ' 格式化為 "YYYY-MM" 格式

            yearMonth = Format(earliestDate, "YYYY-MM")

            

            ' 設置目的檔案夾路徑

            targetFolder = topFolderPath & "\" & yearMonth

            

            ' 如果目的檔案夾不存在,則創建新資料夾

            If Not fso.FolderExists(targetFolder) Then

                fso.CreateFolder(targetFolder)

            End If

            

            ' 設置初始檔案名

            fileName = fso.GetBaseName(file.Name) & "." & fso.GetExtensionName(file.Name)

            newFileName = fileName

            counter = 1

            

            ' 如果目的檔案夾中已存在同名檔,則添加序號

            Do While fso.FileExists(targetFolder & "\" & newFileName)

                newFileName = fso.GetBaseName(file.Name) & "_" & counter & "." & fso.GetExtensionName(file.Name)

                counter = counter + 1

            Loop

            

            ' 移動文件到目的檔案夾

            file.Move targetFolder & "\" & newFileName

        End If

    Next file

    

    ' 遞迴處理子資料夾

    For Each subFolder In folder.SubFolders

        Call ProcessFolder(subFolder, fso, topFolderPath, fileExtensions)

    Next subFolder

End Sub


' 函數:檢查陣列中是否包含指定值

Function IsInArray(value As Variant, arr As Variant) As Boolean

    Dim element As Variant

    IsInArray = False

    For Each element In arr

        If element = value Then

            IsInArray = True

            Exit Function

        End If

    Next element

End Function


' 函數:獲取最早的日期

Function GetEarliestDate(date1 As Date, date2 As Date, date3 As Date) As Date

    GetEarliestDate = Application.WorksheetFunction.Min(date1, date2, date3)

End Function

代碼說明:


頂層資料夾路徑和檔副檔名:topFolderPath 變數指定要處理的頂層資料夾路徑,請將其替換為實際的路徑。fileExtensions 陣列包含要處理的檔案類型副檔名。


遍歷資料夾和文件:ProcessFolder 副程式遞迴遍歷指定資料夾及其所有子資料夾中的每個檔,並調用 IsInArray 函數檢查檔副檔名是否在目標副檔名清單中。


日期比較和分類:對於每個檔,獲取其創建日期、修改日期和訪問日期,並計算最早的日期。然後按 YYYY-MM 格式分類到對應的資料夾中。如果目的檔案夾不存在,則創建新的資料夾。


處理檔案名衝突:如果目的檔案夾中已存在同名檔,則添加序號以避免檔案名衝突。


輔助函數:IsInArray 函數用於檢查檔副檔名是否在目標副檔名清單中,GetEarliestDate 函數用於獲取三個日期中的最早日期。


運行此宏後,指定頂層資料夾及其所有子資料夾中的所有照片和視頻檔將移到最上層資料夾,並按最早日期的年月分類到對應的資料夾中。如果檔案名重複,將自動在檔案名後添加序號。


使用Gemini撰寫投資策略執行碼

 本週我嘗試使用 AI 來測試「蹺蹺板投資策略」。有趣的是,付費版 ChatGPT 在撰寫較複雜的策略程式碼時,表現並不如預期,反而是免費版的 Gemini 表現更為出色。不僅能快速生成可執行的程式,還能在我進行策略修正的過程中,協助將提示詞進一步結構化,讓程式更貼近我原本的投資...