Compare commits

...

2 Commits

Author SHA1 Message Date
cdricms
bc1abfdebc Removed jsonResult 2025-12-06 17:32:34 +01:00
cdricms
a4880b9fe1 Nutriments are now iterable 2025-12-06 17:31:56 +01:00

View File

@@ -2,7 +2,7 @@ import Foundation
import Units
@dynamicMemberLookup
public struct Nutriments: Codable, Sendable {
public struct Nutriments: Codable, Sendable, Sequence {
// We separate values (Doubles) and units (Strings) for efficient, thread-safe storage
private let values: [String: Double]
private let units: [String: String]
@@ -49,6 +49,43 @@ public struct Nutriments: Codable, Sendable {
let kebabName = member.camelCaseToKebabCase()
return Nutrient(name: kebabName, values: values, units: units)
}
// MARK: - Sequence Conformance
// Allows: nutriments.forEach { nutrient in ... }
public func makeIterator() -> AnyIterator<Nutrient> {
// 1. Collect all keys from values and units
let allKeys = Set(values.keys).union(units.keys)
// 2. Extract unique base names (e.g., "energy-kcal_100g" -> "energy-kcal")
let baseNames = allKeys.compactMap { key -> String? in
// Filter out keys that are not nutrient properties
guard !key.isEmpty else { return nil }
// Remove common suffixes to find the "root" nutrient name
let suffixes = [
"_100g", "_serving", "_unit", "_value", "_prepared", "_label",
]
var name = key
// Sort suffixes by length (descending) to avoid partial matches
for suffix in suffixes {
if let range = name.range(of: suffix) {
name.removeSubrange(range)
}
}
return name
}
// 3. Create a unique sorted list
let uniqueNames = Set(baseNames).sorted()
var iterator = uniqueNames.makeIterator()
// 4. Return an iterator that produces `Nutrient` views
return AnyIterator {
guard let name = iterator.next() else { return nil }
return Nutrient(name: name, values: self.values, units: self.units)
}
}
}
// MARK: - Nutrient View