arrays - Swift - 在一个大的时间范围内按一年中的一周对一系列项目进行分组

标签 arrays swift date multidimensional-array mapping

我目前正在开发一个项目,该项目需要我操作一个带有日期和 double 值的对象数组。我能够将其分解为年份字典,然后将这些嵌套数组分解为当年的几周。不幸的是,一年中的第一周经常出现在其中一年和随后的年份中。

我想要实现的是一个数组或字典,其中包含按周分组的所有日期以及该组中所有金额的总和。

我已经尝试过按 .weekOfYear 对它们进行分组,但是这并没有考虑年份本身,如果两个日期相隔一年以上,我总是只会有一个 52 个条目长的数组。

我还通过使用 Calendar.current.ordinality(of: .weekOfYear, in: .era, for: 'date') 来研究使用一周的序数 但它被转换为整数,我不知道如何将其返回到日期

下面是我在 xCode Playground 中使用的代码的副本及其输出

import Foundation

let cal = Calendar.current

extension Date {
    var year: Int {
        return cal.component(.year, from: self)
    }
    var week: Int {
        return cal.component(.weekOfYear, from: self)
    }
    var weekAndYear: DateComponents {
        return cal.dateComponents([.weekOfYear, .year], from: self)
    }
}

struct Item {
    var date: Date
    var amount: Double
}

let startDate: Date = cal.date(from: DateComponents(year: 2018, month: 12, day: 2))!
let endDate: Date = cal.date(from: DateComponents(year: 2019, month: 1, day: 28))!

// Here I'm creating dummy items for each date between our date range
func setUpItems (startDate: Date, endDate: Date) -> [Item] {
    var date = startDate
    var inputArray: [Item] = []

    let dateCount = cal.dateComponents([.day], from: startDate, to: endDate).day
    let valuePerDay: Double = 1000 / Double(dateCount!)
    let lowerLim = valuePerDay - (valuePerDay / 2)
    let upperLim = valuePerDay + (valuePerDay / 2)

    while date < endDate {
        let input = Double.random(in: lowerLim...upperLim).rounded()
        inputArray.append(Item(
            date: date,
            amount: input
        ))
        date = cal.date(byAdding: .day, value: 1, to: date)!
    }

    return inputArray
}

let itemArray = setUpItems(startDate: startDate, endDate: endDate)


let grouppedByYear = Dictionary(grouping: itemArray, by: { $0.date.year })

let grouppedByYearThenWeek = grouppedByYear
    .mapValues{(yearArray: [Item]) -> Dictionary<Int, Double> in
        return Dictionary(grouping: yearArray, by: { $0.date.week })
            .mapValues{ (value: [Item]) in
                return value.map{ $0.amount }.reduce(0, +)
        }
    }

print("Grouped by week")
print(grouppedByYearThenWeek)

由此您可以预期输出如下所示

Grouped by week
[2018: [49: 127.0, 52: 125.0, 50: 119.0, 51: 113.0, 1: 39.0],
  2019: [3: 124.0, 4: 122.0, 5: 19.0, 1: 87.0, 2: 121.0]]

我希望最终得到一本不会根据年份分割一周的字典

[2018: [49: 127.0, 52: 125.0, 50: 119.0, 51: 113.0],
  2019: [3: 124.0, 4: 122.0, 5: 19.0, 1: 126.0, 2: 121.0]]

// or potentially

[["49 2018": 127.0, "52 2018": 125.0...],
  ["3 2019": 124.0, "4 2019": 122.0...]]

任何帮助将不胜感激。

最佳答案

Unfortunately the first week of the year is often present in one of the years and the following.

是的。但如果您要检索一年中的第几周,则使用 .year 检索它是没有意义的。您希望将 .yearForWeekOfYear.weekOfYear 结合使用:

var weekAndYear: DateComponents {
    return cal.dateComponents([.weekOfYear, .yearForWeekOfYear], from: self)
}

var yearForWeekOfYear: Int {
    return cal.component(.yearForWeekOfYear, from: self)
}

您可能会发现“一周开始”计算属性很有用:

var startOfWeek: Date {
    let components = cal.dateComponents([.yearForWeekOfYear, .weekOfYear], from: self)
    return cal.date(from: components)!
}

这取决于您想要如何对待 2018 年 12 月 31 日。您希望它出现在 2019 年的第一周吗(就像标准的 weekOfYearyearForWeekOfYear code> 确实),或者您想将其归因于“2018 年第 53 周”。简而言之,您是否要将 2018 年 12 月 30 日开始的一周视为一周(上面将实现),还是要将其分开,将一周的开始视为 2018 年第 53 周及其后一部分2019 年第 1 周是哪一周?

关于arrays - Swift - 在一个大的时间范围内按一年中的一周对一系列项目进行分组,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/54464912/

相关文章:

swift - Swift 中包含 "or"的 if 语句

ios - swift :围绕给定数字创建范围

ios - 在 HealthKit 中请求授权 : why the result is always successful?

php - 在日期范围列表中省略多余的月份和年份

php - 我如何从年月 2019-03 减去一个月

javascript - 无法调用未定义的方法 'split' - 从函数调用

java - 数组中的随机访问

java - Groovy 用可能的字符串分割字符串

Java:在 HTTP Post 中发送带有其他参数的 byte[]

swift - tableViewCells 中的 collectionViews 之间的通信。这个tableView在另一个tableViewCell中