Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
141 views
in Technique[技术] by (71.8m points)

ios - Grouping Array of Objects by Custom Time Intervals

I have an array of posts which I currently group by day. I use the below functions to do so;

private func splitDay(from date: Date) -> Date {
    let calendar = Calendar.current
    let components = calendar.dateComponents([.year, .month, .day], from: date)
    return calendar.date(from: components)!
}

private func sectionPosts(posts: [Post]) {
    let groups = Dictionary(grouping: posts) { (posts) in
        return splitDay(from: Date(timeIntervalSince1970: posts.createdOn))
    }
    self.sections = groups.map { (date, posts) in
        return PostSection(date: date, posts: posts)
    }
}

However, i'd like to implement a custom grouping which would be the following;

  1. Today
  2. Yesterday
  3. This Week
  4. This Month
  5. Older

How would I build this into my grouping function? My section struct is like such;

struct PostSection {
    var date: Date
    var posts: [Post]
}
question from:https://stackoverflow.com/questions/65895186/grouping-array-of-objects-by-custom-time-intervals

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Answer

0 votes
by (71.8m points)

Since you are trying to group your data into groups such as "today", "yesterday", "this week" and "this month", you should first create a type to represent these groups:

enum PostGroup {
    case today
    case yesterday
    case thisWeek
    case thisMonth
    case older
    case coming // added "coming" group so that the groups cover all possible dates
}

Then your PostSection struct would have a PostGroup property, rather than a Date property:

struct PostSection {
    let group: PostGroup
    let posts: [Post]
}

Now we just need a function that goes (Post) -> PostGroup that we can pass to Dictionary(grouping:by:). This can be implemented just by comparing the date components of the post date with that of today:

func group(for post: Post) -> PostGroup {
    let today = Date()
    let calendar = Calendar.current
    let postDateComponents = calendar.dateComponents([.year, .month, .day], from: post.createdOn)
    let todayDateComponents = calendar.dateComponents([.year, .month, .day], from: today)
    if postDateComponents == todayDateComponents {
        return .today
    }
    let daysDifference = calendar.dateComponents([.day], from: postDateComponents, to: todayDateComponents)
    if daysDifference.day == 1 {
        return .yesterday
    }
    let postWeekComponents = calendar.dateComponents([.weekOfYear, .yearForWeekOfYear], from: post.createdOn)
    let todayWeekComponents = calendar.dateComponents([.weekOfYear, .yearForWeekOfYear], from: today)
    if postWeekComponents == todayWeekComponents {
        return .thisWeek
    }
    if postDateComponents.year == todayDateComponents.year &&
        postDateComponents.month == todayDateComponents.month {
        return .thisMonth
    }
    if post.createdOn < today {
        return .older
    } else {
        return .coming
    }
}

To finish it off:

private func sectionPosts(posts: [Post]) {
    let groups = Dictionary(grouping: posts, by: group(for:))
    self.sections = groups.map { (group, posts) in
        return PostSection(group: group, posts: posts)
    }
}

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome to OStack Knowledge Sharing Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...