我有一组看起来像这样的元组:
[("07-20-2016", 2), ("07-22-2016", 5.0), ("07-21-2016", 3.3333333333333335)]
它包含一个日期的字符串和一个情绪的双重字母(心情小于或等于3表示那天是美好的一天)。 我想弄清楚如何创造美好的一天。
所以我认为我首先需要做的是对元组数组进行排序,按日期排序。 然后我需要计算低于心情值3的元组,如果它们在一行中。在这种情况下,结果将是1,因为只有1天低于3。
如果我有一系列元组,如:
[("07-22-2016", 5.0), ("07-21-2016", 3), ("07-20-2016", 2), ("07-19-2016", 1), ("07-18-2016", 1), ("07-16-2016", 2), ("07-15-2016", 3)]
它的结果是4,因为连续的最大天数低于3是4.它不是6的原因是因为" 07-17-2016& #34;不存在。
请帮我解决这个问题。我知道这里有很多用户比我聪明。你能解决这个问题吗?
答案 0 :(得分:2)
这是我找到的答案。
func datesToStreaks(input: [NSDate]) -> [[NSDate]] {
var ranges:[[NSDate]] = [[]]
input.forEach { currentDay in
var lastRange = ranges.last ?? []
if let lastDate = lastRange.last {
if lastDate.dateByAddingTimeInterval(86400).isEqualToDate(currentDay) {
lastRange.append(currentDay)
ranges.removeLast()
ranges.append(lastRange)
}
else {
ranges.append([currentDay])
}
}
else {
lastRange.append(currentDay)
ranges.removeLast()
ranges.append(lastRange)
}
}
return ranges
}
let input = [("07-22-2016", 5.0), ("07-21-2016", 3), ("07-20-2016", 2), ("07-19-2016", 1), ("07-18-2016", 1), ("07-16-2016", 2), ("07-15-2016", 3)]
let sortedDays:[NSDate] = input
.filter { (date, mood) in
mood <= 3.0}
.map { (date, mood) in
return date}
.flatMap{ date in
let dateFormatter = NSDateFormatter()
dateFormatter.dateFormat = "MM/dd/yyyy"
return dateFormatter.dateFromString(date)
}
.sort{$0.0.earlierDate($0.1).isEqualToDate($0.0)}
let maxStreak = datesToStreaks(sortedDays)
.map{$0.count}
.reduce(0, combine: {return max($0,$1)})
print(maxStreak) // 4
答案 1 :(得分:2)
首先,正如matt建议的那样,制作更好的数据类型。这种语言使结构非常方便。我们需要每个条目都有一个日期和心情分数。易于peasy。
import Foundation
struct JournalEntry {
let date: NSDate
let score: Double
var isGoodDay: Bool { return self.score <= 3.0 }
}
(计算出的isGoodDay
属性将使以后的生活更加轻松。)
现在我们需要将元组的原始列表转换为这些结构的列表。这很简单。创建一个日期解析器,并使用map
在元组类型和结构之间进行转换:
typealias RawEntry = (String, Double)
func parseRawEntries<S: SequenceType where S.Generator.Element == RawEntry>
(rawEntries: S)
-> [JournalEntry]
{
let parser = NSDateFormatter()
parser.dateFormat = "MM-dd-yyyy"
// Use guard and flatMap because dateFromString returns an Optional;
// you might prefer to throw an error to indicate that the data are
// incorrectly formatted
return rawEntries.flatMap { rawEntry in
guard let date = parser.dateFromString(rawEntry.0) else {
return nil
}
return JournalEntry(date: date, score: rawEntry.1)
}
}
转换后我们需要通过列表测试两个条件:首先,那些日子是“好”然后那对好日子是连续的。我们在数据结构本身中有这种辅助方法来测试前者。让我们为连续部分创建另一个辅助函数:
/* N.B. for brevity this assumes first and second are already sorted! */
func entriesConsecutive(first: JournalEntry, _ second: JournalEntry) -> Bool {
let calendar = NSCalendar.currentCalendar()
let dayDiff = calendar.components(.Day,
fromDate: first.date,
toDate: second.date,
options: NSCalendarOptions(rawValue: 0))
return dayDiff.day == 1
}
在每个枚举步骤中,我们将获得当前条目,但我们还需要前一个或下一个,以便我们可以测试连续性。我们显然也希望跟踪条纹的数量,因为我们发现它们。让我们为它做另一种数据类型。 (lastEntry
而不是nextEntry
的原因很快就会明确。)
struct Streak {
let lastEntry: JournalEntry
let count: UInt
}
这是有趣的部分:迭代数组,构建Streak
s。这可以通过for
循环完成。但是,通过计算和聚集每个新项目来消耗序列是一种已知模式。它被称为“folding”; Swift使用备用术语reduce()
。
将序列缩减为组,或者在跟踪某些事物的同时,也是众所周知的模式:组合值本身就是一个集合。在每个步骤中,您将检查新项目以及还原中的最新值。减少的新值 - 从组合函数返回的内容 - 仍然是集合,可以更新先前的值或附加新值。
上面的Streak
数据类型将使缩减中的元素:这就是它使用 last 条目的原因。每一步,我们都会保存JournalEntry
并在下一步检查它。
对于条纹,我们只关心“好”的日子。让我们让生活变得简单,filter
就可以了。let goodDays = journal.filter { $0.isGoodDay }
我们需要第一个条目,这样才能在第一步中进行比较。如果由于某种原因 没有好日子,这也是一个拯救的机会。
guard let firstEntry = goodDays.first else {
return []
}
第一个条目进入Streak
对象,该对象将进入将成为缩减的集合:let initial = [Streak(lastEntry: firstEntry, count: 1)]
,我们已准备就绪。完整的函数看起来像这样(我将让注释解释reduce中的过程):
func findStreaks(in journal: [JournalEntry]) -> [Streak] {
let goodDays = journal.filter { $0.isGoodDay }
guard let firstEntry = goodDays.first else {
return []
}
let initial = [Streak(lastEntry: firstEntry, count: 1)]
return
// The first entry is already used; skip it.
goodDays.dropFirst()
.reduce(initial) {
(reduction: [Streak], entry: JournalEntry) in
// Get most recent Streak for inspection
let streak = reduction.last! // ! We know this exists
let consecutive = entriesConsecutive(streak.lastEntry,
entry)
// If this is the same streak, increment the count by
// replacing the previous value.
// Otherwise add a new Streak with count 1.
let newCount = consecutive ? streak.count + 1 : 1
let streaks = consecutive ?
Array(reduction.dropLast()) :
reduction
return streaks +
[Streak(lastEntry: entry, count: newCount)]
}
}
现在,回到顶层,事情很简单。原始数据:
let rawEntries = [("07-22-2016", 5.0), ("07-21-2016", 3), ("07-20-2016", 2), ("07-19-2016", 1), ("07-18-2016", 1), ("07-16-2016", 2), ("07-15-2016", 3)]
将其转换为相关的数据类型,在我们进入时立即按日期排序。
let journal = parseRawEntries(rawEntries).sort { $0.date < $1.date }
计算条纹:
let streaks = findStreaks(in: journal)
然后你想要的结果是let bestStreakLen = streaks.map({ $0.count }).maxElement()
(小记:使用NSDate
比较<
需要新功能:
func <(lhs: NSDate, rhs: NSDate) -> Bool {
let earlier = lhs.earlierDate(rhs)
return earlier == lhs
}
)
答案 2 :(得分:1)
你可以先建立好心情和坏心情的条纹数组,然后过滤或减少它来分析streeks:
Incorrect