使用功能技术来发现 NSIndexPath

Use a functional technique to discover an NSIndexPath

使用 mapfilterreduce 和朋友们,必须有一种更具表现力的方式来做到这一点。

背景:
categories 属性 是一个 [Category]?,其中每个元素都有一个 videos 属性 类型 [Video]

我正在尝试查找 video 的索引路径。

    var indexPath: NSIndexPath?
    for var i = 0; i < categories?.count ; ++i {
        for var j = 0; j < categories?[i].videos.count ; ++j {
            if categories?[i].videos[j] == video {
                indexPath = NSIndexPath(forRow: j, inSection: i)
            }
        }
    }

    if let indexPath = indexPath {
        tableView.reloadRowsAtIndexPaths([ indexPath ], withRowAnimation: UITableViewRowAnimation.Automatic)
    }

如果您很少这样做,请创建一个生成器,该生成器 returns 索引路径和视频的元组,然后根据您需要的视频过滤视频

如果你制作一个枚举生成器,它主要是将循环移动到它自己的对象中。 categoryIndex 和 videoIndex 成为生成器中的 vars,next 基本上执行 for 循环语句的第 2/3 个子句所做的事情

现在,您正在高效地使用视频索引路径字典。

如果您经常进行此查找并且很少更改集合中的数据,维护双向字典 (video -> IP) 和 (IP->video) 可能会更快,那么这是一个快速操作找到项目。生成器是创建该数据结构的一种方式,但老实说,如果性能成为问题,您必须使用分析器

一个可能的解决方案(写在Swift2):

let indexPaths = categories?.enumerate().flatMap() { (section, aCategory) in
    aCategory.videos.enumerate().filter() { (_, aVideo) in
        aVideo == video
    }.map { (row, _) in
        NSIndexPath(forRow: row, inSection: section)
    }
} ?? []

indexPathsall 匹配索引路径的数组(或空数组)。如果您不 need/like,请使用

let indexPath = categories?.enumerate().flatMap() { (section, aCategory) in
    aCategory.videos.enumerate().filter() { (_, aVideo) in
        aVideo == video
    }.map { (row, _) in
        NSIndexPath(forRow: row, inSection: section)
    }
}.first

相反,这是一个可选的索引路径。

categories?.enumerate()(section, aCategory) 的序列 对。对于每个类别,aCategory.videos.enumerate() 是一个 (row, aVideo) 对的序列。这个序列被过滤 根据搜索词,过滤后的对被映射 到索引路径。

所以传递给flatMap()的转换结果是一个数组 匹配项的索引路径,每个类别一个数组。 flatMap() 将它们连接到一个数组中。

Swift 1.2 中会是

let indexPaths = flatMap(enumerate(categories ?? [])) { (section, aCategory) in
    filter(enumerate(aCategory.videos)) { (_, aVideo) in
        aVideo == video
    }.map { (row, _) in
        NSIndexPath(forRow: row, inSection: section)
    }
}

这不是最实用的,也不是最简洁的,但对我来说它似乎很易读。假设要查找的视频是唯一的。

var location: NSIndexPath? = nil
for (section, category) in enumerate(categories ?? []) {
    if let row = find(category.videos, video) {
        location = NSIndexPath(forRow: row, inSection: section)
        break
    }
}