Home > Enterprise >  How to split array based on 1 or more days difference between date of array element?
How to split array based on 1 or more days difference between date of array element?

Time:12-17

How to split array based on 1 or more days difference between date of array element?

Consider following array:

[
 {"Name":"A", "Date":"01/01/2021"},

 {"Name":"B", "Date":"02/01/2021"},

 {"Name":"C", "Date":"05/01/2021"},

 {"Name":"D", "Date":"06/01/2021"},

 {"Name":"E", "Date":"09/01/2021"}
]

Now split this array to 3 arrays. as following

  1. [{"Name":"A", "Date":"01/01/2021"}, {"Name":"B", "Date":"02/01/2021"}]
  2. [{"Name":"C", "Date":"05/01/2021"}, {"Name":"D", "Date":"06/01/2021"}]
  3. [{"Name":"E", "Date":"09/01/2021"}]

The array should split with object which have continuous dates.

CodePudding user response:

I have Implemented extension on Array to achieve what I needed. split function expects array sorted in ascending order.

    extension Array {
    
    public func split(by dateComponents: Calendar.Component, diffrence:Int, transform: (Element) -> Date?) -> [[Element]]{
        let initialResult:(groupedArray:[[Element]],noDateArray:[Element]) = ([],[])
       let splitArray = reduce(initialResult) { partialResult, element in
           if let nextDate = transform(element){
               if let oldElement = partialResult.groupedArray.last?.last {
                   if let oldDate = transform(oldElement){
                       if nextDate.interval(ofComponent: dateComponents, fromDate: oldDate) == diffrence {
                           let lastIndex = partialResult.groupedArray.count - 1
                           var newResult = partialResult
                           newResult.groupedArray[lastIndex].append(element)
                           return newResult
                       }else{
                           var newResult = partialResult
                           newResult.groupedArray.append([element])
                           return newResult
                       }
                   }else{ // This case wont be executed but need to handle tosilence compilation errors.
                       var newResult = partialResult
                       newResult.groupedArray.append([element])
                       return newResult
                   }
                }else{
                    var newResult = partialResult
                    newResult.groupedArray.append([element])
                    return newResult
                }
           }else{
               var newResult = partialResult
               newResult.noDateArray.append(element)
               return newResult
           }
        }
        var newSplitArray = splitArray.groupedArray
        if !splitArray.noDateArray.isEmpty {
            newSplitArray.append(splitArray.noDateArray)
        }
        return newSplitArray
    }
}

CodePudding user response:

I am going to make the assumption that your list is presorted (based on the fact that the list you gave for consideration was presorted). If not, you would need to sort this list in order to be able to use this method.

   a = [{"Name":"A", "Date":"01/01/2021"}, 
   {"Name":"B", "Date":"02/01/2021"}, 
   {"Name":"C", "Date":"05/01/2021"},
   {"Name":"D", "Date":"06/01/2021"}, 
   {"Name":"E", "Date":"09/01/2021"}]

First: make a function that returns either True or False based on your definition of continuous days.

   def datesContinuous(date1, date2):
      return true if the dates are continuous, otherwise false

Since your desired output is essentially a list of lists, we will go through the given array "a" and if the element we are looking at is "continuous" then it will be appended to the current list we are working on in output. If it is not continuous, we will start a new list and append that list to output.

   lastElement = "01/01/0000"
   output = []
   counter = 0
   for element in a:
     if lastElement = "01/01/0000":
       lastElement = element
       output.append([element])
       continue
     if datesContinuous(element, lastElement):
       output[counter].append(element)
     else:
       counter  =1
       output.append([element])
     
  • Related