从一组自定义对象计算键的每日总计

时间:2017-02-19 17:38:13

标签: arrays swift sorting

我知道我的标题有些令人困惑,但让我解释一下: 我已经有一段时间了,我似乎无法解决这个问题。

首先,这是我的一些代码:

struct CalorieLog {

  var date: Date
  var calories: Int

} 

  var logs: [CalorieLog] = []

  func logCalories() {

  //... calculate calories to log

  let currentDate: Date = Date()
  let calories: Int = calculatedCalories

  logs.append(CalorieLog(date: currentDate, calories: calculatedCalories))

}

现在如何在白天对日志数组中的CalorieLog项目进行分组,并获得每天记录的所有卡路里的总和?也许可以将它们分成一系列字典?例如字典(字符串:Int)使得(日:总卡路里)

请不要苛刻我仍然是新手开发者。提前谢谢。

3 个答案:

答案 0 :(得分:1)

您尝试做的很多事情都可以使用Swift的mapsortedfilteredreduce函数来完成。

struct CalorieLog {

    var date: Date
    var calories: Int

}

var logs: [CalorieLog] = []

// I changed your method to pass in calculatedCalories, we can make that random just for learning purposes. See below
func logCalories(calculatedCalories: Int) {

    let currentDate: Date = Date()

    logs.append(CalorieLog(date: currentDate, calories: calculatedCalories))

}

// This is a method that will calculate dummy calorie data n times, and append it to your logs array
func addDummyCalorieData(n: Int, maxRandomCalorie: Int) {

    for _ in 1...n {
        let random = Int(arc4random_uniform(UInt32(maxRandomCalorie)))

        logCalories(calculatedCalories: random)
    }

}

// Calculate 100 random CalorieLog's with a max calorie value of 1000 calories
addDummyCalorieData(n: 100, maxRandomCalorie: 1000)

// Print the unsorted CalorieLogs
print("Unsorted Calorie Data: \(logs)")

// Sort the logs from low to high based on the individual calories value. 
let sortedLowToHigh = logs.sorted { $0.calories < $1.calories }

// Print to console window
print("Sorted Low to High: \(sortedLowToHigh)")

// Sort the CalorieLogs from high to low
let sortedHighToLow = logs.sorted { $1.calories < $0.calories }

// Print to console window
print("Sorted High to Low: \(sortedHighToLow)")

// Sum
// This will reduce the CaloreLog's based on their calorie values, represented as a sum
let sumOfCalories = logs.map { $0.calories }.reduce(0, +)

// Print the sum
print("Sum: \(sumOfCalories)")

如果您想将CalorieLogs映射为一系列词典,您可以这样做:

let arrayOfDictionaries = logs.map { [$0.date : $0.calories] }

然而,这种效率低下。你为什么想要一系列字典?如果您只是想跟踪特定日期消耗/燃烧的卡路里,您可以只创建一个字典,其中日期是您的密钥,而Int数组是表示该日所有卡路里的值。你可能只需要一本字典,即

var dictionary = [Date : [Int]]()

然后你可以通过说dictionary[Date()]找到约会的所有卡路里。但请记住,您必须拥有确切的日期和时间。您可能希望将字典中的键更改为String类似于2/19/2017之类的日期,这可以更容易地进行比较。在设计模型时必须考虑到这一点。

答案 1 :(得分:1)

很大程度上取决于你所说的“日”。因此,在这个高度简化的示例中,我只使用默认定义,即日历为特定日期定义的日期(不考虑时区现实)。

以下是一些基本数据:

struct CalorieLog {
    var date: Date
    var calories: Int
}
var logs: [CalorieLog] = []
logs.append(CalorieLog(date:Date(), calories:150))
logs.append(CalorieLog(date:Date(), calories:140))
logs.append(CalorieLog(date:Date()+(60*60*24), calories:130))

现在我们构建一个字典,其中键是日期日的常规,值是包含该日作为日期的所有日志的数组:

var dict = [Int:[CalorieLog]]()
for log in logs {
    let d = log.date
    let cal = Calendar(identifier: .gregorian)
    if let ord = cal.ordinality(of: .day, in: .era, for: d) {
        if dict[ord] == nil {
            dict[ord] = []
        }
        dict[ord]!.append(log)
    }
}

你的CalorieLogs现在已经成熟了几天!现在可以很容易地浏览该字典并将每个天的日志数组的卡路里相加。我不知道你最终想要对这些信息做些什么,所以我只是打印它,以证明我们的字典组织是有用的:

for (ord,logs) in dict {
    print(ord)
    print(logs.reduce(0){$0 + $1.calories})
}

答案 2 :(得分:1)

要按日期排序日志,您只需执行以下操作:

logs.sorted(by: { $0.date < $1.date })

要获得一个字典,将一天映射到当天的卡路里总和,您可以这样做:

let dateFormatter = DateFormatter()
dateFormatter.dateFormat = "dd MMM yyyy"

var calorieCalendar = [String: Int]()
for log in logs {
    let date = dateFormatter.string(from: log.date)
    if let _ = calorieCalendar[date] {
        calorieCalendar[date]! += log.calories
    } else {
       calorieCalendar[date] = log.calories
    }
}

对于像这样的logs设置

logs.append(CalorieLog(date: Date(), calories: 1))
logs.append(CalorieLog(date: Date.init(timeIntervalSinceNow: -10), calories: 2))
logs.append(CalorieLog(date: Date.init(timeIntervalSinceNow: -60*60*24*2), calories: 3))

上面的代码将生成如下字典:

["17 Feb 2017": 3, "19 Feb 2017": 3]