【问题标题】:Swift: Find date in array that is closest in timeSwift:在数组中查找时间最接近的日期
【发布时间】:2018-10-12 07:50:41
【问题描述】:

这是我第一次使用 swift(macOS 命令行应用程序)进行开发。

我正在遍历一个文件夹中的所有 jpeg 文件,获取那些在 EXIF 数据中没有 GPS 信息的文件,并为每个图像找到时间最接近的 GPS 数据( Exif 时间戳)。然后我想从图像中复制 GPS 数据。

我有一个包含文件名(字符串)、日期(日期)和 GPS(字典)的结构,并为所有文件创建了一个数组(我没有在此处粘贴函数 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
        }
    }
}

【问题讨论】:

    标签: swift date


    【解决方案1】:

    如果“最近”是指“最新”,那么这是我为您提供的解决方案:

    首先是一些对我们有帮助的扩展:

    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 正在对先前操作的剩余内容进行排序(并且因为使用了 orderedSetfilter 之前,它可能需要排序的文件较少)

    编辑:

    起初我误解了这个问题。我希望这就是你的意思:

    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
    }
    

    【讨论】:

    • 对不起,如果我不清楚。最接近的意思是 .date 最接近我们当前迭代的项目(请参阅我的答案)。但感谢您的意见。我一定会看看的!
    • 现在当我再次阅读您的问题时,我发现我完全误解了它。对不起:/我认为如果你用答案中的代码更新你的问题而不是发布它会更好;)
    • 感谢您抽出宝贵时间。由于我是 swift 新手,因此每一个见解都是有帮助的。现在将我的答案作为对问题的编辑。
    • @tzippy,我也更新了我的答案。这可能是您已经完成的另一种方式。不确定是否更好。只是不同;)
    猜你喜欢
    • 1970-01-01
    • 2019-07-09
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-08-26
    • 2015-02-08
    • 1970-01-01
    • 2021-09-27
    相关资源
    最近更新 更多