2

I have 2 arrays, both of kind [[String:Any]] , where each element :

["date":Date,"value":CGFloat] //always looks like this

I might even have more than 2 (!)

I would like to create a single array with the same structure that sums all of them (2 or more) for each date that appears in all of them.

If the date of array1 does not appear on the others(array2, etc) I will simply add 0 to the value at array 1 for this specific date.

Is there a simple efficient way to do so ?

Curnelious
  • 1
  • 16
  • 76
  • 150

2 Answers2

1

Instead of dictionaries use structs, it's more convenient:

struct MyStruct {
    let date: Date
    let value: CGFloat
}

Let's create 3 arrays of MyStructs:

let now = Date()
let later = now.addingTimeInterval(3600)
let earlier = now.addingTimeInterval(-3600)

let array1: [MyStruct] = [MyStruct(date: now, value: 1),
                          MyStruct(date: later, value: 2)]
let array2: [MyStruct] = [MyStruct(date: now, value: 3),
                          MyStruct(date: later, value: 4)]
let array3: [MyStruct] = [ MyStruct(date: earlier, value: 5),
                           MyStruct(date: later, value: 6)]

Now, let's group the elements and add the values for the elements with the same date property:

let allArrays = array1 + array2 + array3
let dict = Dictionary(allArrays.map { ($0.date, $0.value) },
                      uniquingKeysWith: { $0 + $1 })

All you have to do now is convert it back to an array of MyStruct:

let newArray = dict.map { MyStruct(date: $0.key, value: $0.value) }

And you can check the results like so:

for element in newArray {
    print("date =", element.date, "value =", element.value)
}
ielyamani
  • 17,807
  • 10
  • 55
  • 90
0

I found a way, assuming data is inside a structure(not a dic) which is a better practice.

I will put all arrays into a single large array, sort it by dates, loop on it and as long as date is equal previous date(or close enough to equality), I will sum the values up. When the next date is different, I will save the date and the sum.

       //create a combined array from all given arrays
        var combined = [RootData]()
        for list in dataSets {combined.append(contentsOf: list)}

        //sort it by dates
        let sortedArray =   combined.sorted {  $0.date < $1.date }

        //new array - sum of all
        var sumData = [RootData]()

        var last:Date = sortedArray[0].date //set starting point
        var sum:CGFloat = 0
        for element in sortedArray
        {
            //same date - accumulate(same is less than 1 sec difference)
            if(abs(element.date.seconds(from: last)) <= 1) {
                sum+=element.value
            }
            //save
            else {
                sumData.append(RootData(value:sum,date:last))
                sum=element.value
            }
            last=element.date
        }
   //last object
    sumData.append(RootData(value:sum,date:last))

    return  averageData

Here RootData is a simple structure for the data with :

value:CGFloat
date:Date

Works as expected. Because dates are not always completely equal , I check equality by assuming 1 second or less is the same date.

Curnelious
  • 1
  • 16
  • 76
  • 150