Swift数组插值填充:计算(日期,体重)数组中的缺失0值
Got it, let's tackle this interpolation problem for your weight data. First, I noticed a tiny typo in your array: (1q.0 , 0.0) should probably be (11.0, 0.0)—I'll use that corrected version (plus a reasonable value for your truncated last entry) to demonstrate the solution.
The standard approach here is linear interpolation, which works perfectly for time-series data like this. The idea is to fill each 0-weight entry using the nearest non-zero values before and after it, calculating a smooth intermediate value.
Step-by-Step Explanation
- Extract Valid Data Points: First, we filter out all entries where the weight is non-zero—these are our reference points for interpolation.
- Iterate and Fill: For each entry in your original array:
- If the weight is already non-zero, leave it as-is.
- If it's zero, find the closest valid point before it and the closest valid point after it.
- Use the linear interpolation formula to compute the missing weight.
Linear Interpolation Formula
Given a left reference point (x₀, y₀) and right reference point (x₁, y₁), the interpolated value for date x is:
y = y₀ + (y₁ - y₀) * (x - x₀) / (x₁ - x₀)
Swift Implementation
Here's a complete, working code example tailored to your data:
typealias Weights = (date: Double, weight: Double) // Corrected and completed version of your input array var myArray: [Weights] = [ (0.0 , 25.4), (1.0 , 0.0), (2.0 , 0.0), (3.0 , 0.0), (4.0 , 0.0), (5.0 , 30.3), (6.0 , 33.5), (7.0 , 0.0), (8.0 , 0.0), (9.0 , 51.2), (10.0 , 0.0), (11.0 , 0.0), (12.0 , 83.1), (13.0 , 0.0), (14.0 , 0.0), (15.0 , 0.0), (16.0 , 143.0), (17.0 , 0.0), (18.0 , 0.0), (19.0 , 0.0), (20.0 , 180.0) ] // Grab all non-zero weight entries to use as reference points let validWeightPoints = myArray.filter { $0.weight != 0.0 } // Loop through each entry and fill zeros with interpolated values for index in myArray.indices { var currentEntry = myArray[index] guard currentEntry.weight == 0.0 else { continue } // Find the nearest valid point BEFORE the current date let leftReference = validWeightPoints.last { $0.date < currentEntry.date } // Find the nearest valid point AFTER the current date let rightReference = validWeightPoints.first { $0.date > currentEntry.date } // Skip if we don't have both references (e.g., leading/trailing zeros) guard let left = leftReference, let right = rightReference else { // Optional: Replace with nearest valid value if you want to handle edge cases // currentEntry.weight = left?.weight ?? right?.weight ?? 0.0 continue } // Calculate interpolated weight using linear formula let slope = (right.weight - left.weight) / (right.date - left.date) let interpolatedWeight = left.weight + slope * (currentEntry.date - left.date) // Update the array with the calculated value myArray[index] = (currentEntry.date, interpolatedWeight) } // Print the result to verify for entry in myArray { print(String(format: "Date: %.1f | Weight: %.2f", entry.date, entry.weight)) }
Notes
- Edge Cases: The code skips leading or trailing zeros where there's only one reference point. If you want to fill those (e.g., use the first valid weight for leading zeros), uncomment the optional line in the guard block.
- Flexibility: This code works even if your date intervals aren't uniform (e.g., if you have missing dates or irregular gaps).
- Precision: The
String(format:)line rounds the weight to two decimal places for readability—adjust as needed.
内容的提问来源于stack exchange,提问作者arakweker

