Объединение массивов словарей по датам - PullRequest
0 голосов
/ 25 ноября 2018

У меня есть 2 массива, оба вида [[String:Any]], где каждый элемент:

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

У меня может быть даже более 2 (!)

Я хотел бы создатьодин массив с одинаковой структурой, которая суммирует их все (2 или более) для каждой даты, которая появляется во всех них.

Если дата массива1 не отображается на других (массив2 и т. Д.), Я просто добавлю 0 к значению в массиве 1 для этой конкретной даты.

Существует ли простой эффективный способсделать это?

Ответы [ 2 ]

0 голосов
/ 25 ноября 2018

Я нашел способ, предполагая, что данные находятся внутри структуры (не dic), что является лучшей практикой.

Я соберу все массивы в один большой массив, отсортирую его по датам, зациклю на неми пока дата равна предыдущей дате (или достаточно близка к равенству), я буду суммировать значения.Когда следующая дата будет другой, я сохраню дату и сумму.

       //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

Здесь RootData представляет собой простую структуру данных с:

value:CGFloat
date:Date

Работает, как ожидалось,Поскольку даты не всегда полностью совпадают, я проверяю равенство, предполагая, что 1 секунда или меньше - это одна и та же дата.

0 голосов
/ 25 ноября 2018

Вместо словарей использовать структуры, это более удобно:

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

Давайте создадим 3 массива MyStruct s:

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)]

Теперь давайте сгруппируем элементы и добавимvalue s для элементов с таким же свойством date:

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

Все, что вам нужно сделать сейчас, - это преобразовать его обратно в массив MyStruct:

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

И вы можете проверить результаты так:

for element in newArray {
    print("date =", element.date, "value =", element.value)
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...