Swift: Найти дату в массиве, который является ближайшим по времени - PullRequest
0 голосов
/ 12 октября 2018

Это мой первый опыт разработки в swift (приложение командной строки macOS).

Я перебираю все файлы jpeg в папке, беру те, у которых нет данных GPS в данных EXIF, и нахожудля каждого другого изображения с данными GPS, которые являются ближайшими по времени (Exif Timestamp).Затем я хочу скопировать данные GPS из изображения.

У меня есть структура с именем файла (String), датой (Date) и GPS (Dictionary) и я создал массив для всех файлов (я не сделал 'Вставьте сюда функцию getFiles()).

struct stFile {
    var name : String
    var date : Date
    var gps : [String : AnyObject]?
}

Затем я сортирую массив по полю даты:

var files = getFiles(folder: "files://FolderToJpegs/")
var filesSorted = files.sorted(by: { $0.date.compare($1.date) == .orderedDescending })

Все, что я мог придумать до сих пор, - это функция, котораянаходит файлы с одинаковой датой (Пропускать файлы с одинаковым именем, потому что это тот же файл, который мы сейчас перебираем):

for file in filesSorted {
    if (file.gps == nil) {
        if let closesdate = filesSorted.first(where: { $0.date.compare(file.date) == ComparisonResult.orderedAscending && $0.name != file.name }) {
            print("The closest date to \(file.date) is \(closesdate.date).")
        }
    }
}

Поскольку я новичок в swift, мне было интересно, есть лиВ версии 4 это уже простой способ сделать это.Один способ, который я предполагаю, состоит в том, чтобы вложить еще одну итерацию в первую и вычислить разницу во времени.

Спасибо!

Редактировать

Хорошо, покаЯ придумал решение, которое вычисляет разницу во времени между одним элементом и каждым другим, у которого есть данные GPS (.gps! = Nil):

for (index, _) in filesSorted.enumerated()
{
    if filesSorted[index].gps == nil
    {
        var timeDiffPrev = Double.greatestFiniteMagnitude
        var closestFile:stFile?

        for fileWithGPS in filesSorted
        {
            if(filesSorted[index].name != fileWithGPS.name && fileWithGPS.gps != nil)
            {
                let timeDiff = abs(filesSorted[index].date.timeIntervalSince(fileWithGPS.date))
                if(timeDiff < timeDiffPrev)
                {
                    closestFile = fileWithGPS
                }
                timeDiffPrev = timeDiff
            }
        }
        if(closestFile != nil)
        {
            filesSorted[index].gps = closestFile?.gps
        }
    }
}

1 Ответ

0 голосов
/ 12 октября 2018

Если под «самым близким» вы подразумеваете «последний», то вот мое решение для вас:

Сначала несколько расширений, которые помогут нам:

extension Collection where Element: Hashable {
    var orderedSet: [Element]  {
        var set = Set<Element>()
        return compactMap { set.insert($0).inserted ? $0 : nil }
    }
}

Благодаря этому расширению мы будемудалить дубликаты из коллекции.Но теперь нам нужно, чтобы ваша структура соответствовала Hashable протоколу.

extension stFile: Hashable {
    static func == (lhs: stFile, rhs: stFile) -> Bool {
        return lhs.name == rhs.name
    }

    func hash(into hasher: inout Hasher) {
        hasher.combine(name)
    }
}

Благодаря вышесказанному мы можем создать такую ​​функцию:

func getLatest() -> stFile? {
    return files.orderedSet.filter({$0.gps != nil}).sorted(by: {$0.date.compare($1.date) == .orderedDescending}).first
}

где:

  • orderedSet удалить дубликаты (файлы с одинаковым именем)
  • filter удалить файлы без данных GPS
  • sorted сортирует то, что осталось от предыдущих операций (и потому что orderedSet и filter использовался ранее, вероятно, он имеет меньше файлов для сортировки)

РЕДАКТИРОВАТЬ:

Сначала я неправильно понял вопрос.Я надеюсь, что это то, что вы имели в виду:

func copyGPS() -> [stFile] {
    let uniqueFiles = files.orderedSet.sorted(by: {$0.date.compare($1.date) == .orderedDescending})
    var filesWithGPS : [stFile] = []
    for file in uniqueFiles {
        if file.gps == nil {
            let gps = uniqueFiles.filter({$0.gps != nil && $0.date > file.date}).first?.gps
            filesWithGPS.append(stFile(name: file.name, date: file.date, gps: gps))
        } else {
            filesWithGPS.append(file)
        }
    }
    return filesWithGPS
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...