这是我第一次在Swift(macOS命令行应用程序)中进行开发。
我要遍历一个文件夹中的所有jpeg文件,将EXIF数据中没有GPS信息的文件复制出来,并为每个图像找到另外一张 GPS数据,这些图像在时间上最近( Exif时间戳)。然后我要从图像中复制GPS数据。
我有一个带有文件名(字符串),日期(Date)和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).")
}
}
}
由于我是新手,所以我想知道版本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
}
}
}
答案 0 :(得分:0)
如果“最接近”是指“最新”,那么这是我为您提供的解决方案:
首先是对我们有帮助的扩展:
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
}