From 4dbde3d17fd5a1f8a894afdc8f1e680540c5fed6 Mon Sep 17 00:00:00 2001 From: Rudi Farkas Date: Sat, 28 Jan 2023 16:45:20 +0100 Subject: [PATCH 1/3] add extension Array where Element == String {func sortedBySuffixAndPrefix()...} --- Sources/RudifaUtilPkg/CollectionExt.swift | 26 +++++++++++++++++++ .../CollectionExtTests.swift | 17 ++++++++++-- 2 files changed, 41 insertions(+), 2 deletions(-) diff --git a/Sources/RudifaUtilPkg/CollectionExt.swift b/Sources/RudifaUtilPkg/CollectionExt.swift index fe47dd7..9c8747a 100644 --- a/Sources/RudifaUtilPkg/CollectionExt.swift +++ b/Sources/RudifaUtilPkg/CollectionExt.swift @@ -118,3 +118,29 @@ public extension Array { return temp } } + +public extension Array where Element == String { + /// Given an array of strings, each optionally sepatated into prefix and suffix by the separator, + /// sort strings aplhabeticall, but grouped by suffix + /// - Parameter separator: defaults to "_" + /// - Returns: sorted array + func sortedBySuffixAndPrefix(separator: String = "_") -> [Element] { + return sorted { a, b -> Bool in + let aComponents = a.components(separatedBy: separator) + let bComponents = b.components(separatedBy: separator) + if aComponents.count == 1, bComponents.count == 1 { + return a < b + } else if aComponents.count == 1 { + return true + } else if bComponents.count == 1 { + return false + } else { + if aComponents[1] == bComponents[1] { + return aComponents[0] < bComponents[0] + } else { + return aComponents[1] < bComponents[1] + } + } + } + } +} diff --git a/Tests/RudifaUtilPkgTests/CollectionExtTests.swift b/Tests/RudifaUtilPkgTests/CollectionExtTests.swift index 75ba1bd..11de874 100644 --- a/Tests/RudifaUtilPkgTests/CollectionExtTests.swift +++ b/Tests/RudifaUtilPkgTests/CollectionExtTests.swift @@ -164,14 +164,14 @@ class CollectionExtTests: XCTestCase { // using the inline predicate let updatedCalendarDataArray = calendarDataArray.updatedPreservingOrder(from: incomingCalendarDataArray, - predicate: { (elt1, elt2) -> Bool in elt1.title == elt2.title }) + predicate: { elt1, elt2 -> Bool in elt1.title == elt2.title }) printClassAndFunc("updatedCalendarDataArray= \(updatedCalendarDataArray.map { $0.string })") XCTAssertEqual(updatedCalendarDataArray.map { $0.string }, expectedResultStringArray) var localCopy = calendarDataArray localCopy.updatePreservingOrder(from: incomingCalendarDataArray, - predicate: { (elt1, elt2) -> Bool in elt1.title == elt2.title }) + predicate: { elt1, elt2 -> Bool in elt1.title == elt2.title }) XCTAssertEqual(localCopy.map { $0.string }, expectedResultStringArray) } @@ -324,4 +324,17 @@ class CollectionExtTests: XCTestCase { XCTAssertEqual(array.moved(where: MockCalendarData(title: "Orchid").sameTitle, to: 3).map { $0.title }, ["Anemone", "Begonia", "Clematis", "Dahlia"]) } + + func test_Array_sortedBySuffixAndPrefix() { + do { + let array = ["1.A", "9.B", "5.A", "7.C", "3.B", "7.A", "4.A", "3", "6", "1", "5.C"] + let sortedArray = array.sortedBySuffixAndPrefix(separator: ".") + XCTAssertEqual(sortedArray, ["1", "3", "6", "1.A", "4.A", "5.A", "7.A", "3.B", "9.B", "5.C", "7.C"]) + } + do { + let array = ["1_A", "9_B", "5_A", "7_C", "3_B", "7_A", "4_A", "3", "6", "1", "5_C"] + let sortedArray = array.sortedBySuffixAndPrefix() + XCTAssertEqual(sortedArray, ["1", "3", "6", "1_A", "4_A", "5_A", "7_A", "3_B", "9_B", "5_C", "7_C"]) + } + } } From 4d56d25548caa6ae159324d9d8fdf344ff851779 Mon Sep 17 00:00:00 2001 From: Rudi Farkas Date: Fri, 6 Jan 2023 15:39:59 +0100 Subject: [PATCH 2/3] add TimerDeltaSigma --- Sources/RudifaUtilPkg/TimerDeltaSigma.swift | 105 ++++++++++++++++++ .../TimerDeltaSigmaTests.swift | 31 ++++++ 2 files changed, 136 insertions(+) create mode 100644 Sources/RudifaUtilPkg/TimerDeltaSigma.swift create mode 100644 Tests/RudifaUtilPkgTests/TimerDeltaSigmaTests.swift diff --git a/Sources/RudifaUtilPkg/TimerDeltaSigma.swift b/Sources/RudifaUtilPkg/TimerDeltaSigma.swift new file mode 100644 index 0000000..89f5a09 --- /dev/null +++ b/Sources/RudifaUtilPkg/TimerDeltaSigma.swift @@ -0,0 +1,105 @@ +// +// TimerDeltaSigma.swift +// RudifaUtilPkg +// +// Created by Rudolf Farkas on 06.01.23. +// Copyright © 2023 Rudolf Farkas. All rights reserved. +// + +import Foundation + +/** + ###Usage examples:### + + Sample usage: + + ```` + func demo_TimerDeltaSigma() { + var tds = TimerDeltaSigma() + for _ in 0 ..< 10 { + tds.printElapsedTimes() + } + print() + for _ in 0 ..< 5 { + tds.printElapsedTimes(.ms) + } + print() + for _ in 0 ..< 5 { + tds.printElapsedTimes(.s) + } + print() + } + ``` + Sample output: + + ``` + Δ 0.000000, Σ 0.000000 s + Δ 0.000082, Σ 0.000082 s + ... + Δ 0.000022, Σ 0.000260 s + Δ 0.000021, Σ 0.000281 s + + Δ 0.000, Σ 0.000 s + ... + Δ 0.000, Σ 0.000 s + + Δ 0, Σ 0 s + ... + Δ 0, Σ 0 s + ``` + */ + +/// TimerDeltaSigma methods print elapsed time (sum since the instance creation and delta since the previous print) +public struct TimerDeltaSigma { + public enum Format: String { + case s + case ms + case μs + } + + typealias Elapsed = (delta: TimeInterval, sigma: TimeInterval) + + /// Create an instance and start time measurement + public init() {} + + private var initialTime: Date? + private var previousTime: Date? + + /// Update times variables and return the result tuple + /// - Returns: (delta, sigma) + private mutating func elapsedTimes() -> Elapsed { + let currentTime = Date() + if let initialTime = initialTime, let previousTime = previousTime { + let sigmaTime = currentTime.timeIntervalSince(initialTime) + let deltaTime = currentTime.timeIntervalSince(previousTime) + self.previousTime = currentTime + return (delta: deltaTime, sigma: sigmaTime) + } else { + initialTime = currentTime + previousTime = currentTime + return (delta: 0, sigma: 0) + } + } + + /// Format the tuple (delta, sigma) per format `fmt` + /// - Parameters: + /// - times: (delta, sigma) + /// - fmt: .s, .ms, .μs + /// - Returns: formatted string, like "Δ 0.000018, Σ 0.000291 s" + private func format(_ times: Elapsed, fmt: Format) -> String { + switch fmt { + case .s: + return String(format: "Δ %.0f, Σ %.0f s", times.delta, times.sigma) + case .ms: + return String(format: "Δ %.3f, Σ %.3f s", times.delta, times.sigma) + case .μs: + return String(format: "Δ %.6f, Σ %.6f s", times.delta, times.sigma) + } + } + + /// Print the times: Δ since the last print, Σ since the instance creation + /// - Parameter fmt: resolution .s, .ms, .μs + public mutating func printElapsedTimes(_ fmt: Format = .μs) { + print(format(elapsedTimes(), fmt: fmt)) + } +} diff --git a/Tests/RudifaUtilPkgTests/TimerDeltaSigmaTests.swift b/Tests/RudifaUtilPkgTests/TimerDeltaSigmaTests.swift new file mode 100644 index 0000000..250646b --- /dev/null +++ b/Tests/RudifaUtilPkgTests/TimerDeltaSigmaTests.swift @@ -0,0 +1,31 @@ +// +// TimerDeltaSigmaTests.swift +// +// +// Created by Rudolf Farkas on 06.01.23. +// + +import XCTest +import RudifaUtilPkg + +final class TimerDeltaSigmaTests: XCTestCase { + override func setUpWithError() throws {} + + override func tearDownWithError() throws {} + + func test_TimerDeltaSigma() { + var tds = TimerDeltaSigma() + for _ in 0 ..< 10 { + tds.printElapsedTimes() + } + print() + for _ in 0 ..< 5 { + tds.printElapsedTimes(.ms) + } + print() + for _ in 0 ..< 5 { + tds.printElapsedTimes(.s) + } + print() + } +} From 23c913fcf14a34b0dcb86e7842ddfe0f22402ba6 Mon Sep 17 00:00:00 2001 From: Rudi Farkas Date: Sat, 7 Jan 2023 22:01:19 +0100 Subject: [PATCH 3/3] add UIImage summary --- Sources/RudifaUtilPkg/UIKItExt.swift | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 Sources/RudifaUtilPkg/UIKItExt.swift diff --git a/Sources/RudifaUtilPkg/UIKItExt.swift b/Sources/RudifaUtilPkg/UIKItExt.swift new file mode 100644 index 0000000..b08657d --- /dev/null +++ b/Sources/RudifaUtilPkg/UIKItExt.swift @@ -0,0 +1,21 @@ +// +// UIKItExt.swift +// +// +// Created by Rudolf Farkas on 07.01.23. +// Copyright © 2023 Rudolf Farkas. All rights reserved. +// + +#if os(iOS) + import UIKit + + extension UIImage { + /// Return a summary of inmage size data + /// - Example: (700.0, 700.0) x 1.0, 609693 bytes + var summary: String { + let data = jpegData(compressionQuality: 1.0) ?? pngData() + let bytes = "\(data?.count ?? 0)" + return "\(size) x \(scale), \(bytes) bytes" + } + } +#endif