Ios 如何在Swift中创建安全数组子集?
我正在尝试一种安全的方法来拆分数组 我知道你可以用数组的一个子集来做这样的事情:Ios 如何在Swift中创建安全数组子集?,ios,arrays,swift,Ios,Arrays,Swift,我正在尝试一种安全的方法来拆分数组 我知道你可以用数组的一个子集来做这样的事情: let arr = [1,2,3,4,5] print(arr[0..<3]) 程序将崩溃 我想做一个数组扩展,它不会崩溃,而是产生尽可能多的元素以便打印 [4,5] subscript(safe range: Range) -> Element? { } 您可以执行以下操作: extension Array { subscript(safe range: Range<Index&g
let arr = [1,2,3,4,5]
print(arr[0..<3])
程序将崩溃
我想做一个数组扩展,它不会崩溃,而是产生尽可能多的元素以便打印
[4,5]
subscript(safe range: Range) -> Element? {
}
您可以执行以下操作:
extension Array {
subscript(safe range: Range<Index>) -> ArraySlice<Element>? {
if range.endIndex > endIndex {
if range.startIndex >= endIndex {return nil}
else {return self[range.startIndex..<endIndex]}
}
else {
return self[range]
}
}
}
let a = [1,2,3]
a[safe: 1...3] // [2,3]
扩展数组{
下标(安全范围:范围)->ArraySlice{
如果range.endIndex>endIndex{
如果range.startIndex>=endIndex{return nil}
else{return self[range.startIndex..来自Array
的startIndex
文档:
始终为零,这是非空时第一个元素的索引
因此,可以假定startIndex
是第一个元素的索引(如果有)
扩展数组{
下标(安全范围:范围)->[元素]{
guard range.startIndex>=self.startIndex else{return nil}
guard range.endIndex您可以使用
extension RandomAccessIndexType {
@warn_unused_result
public func advancedBy(n: Self.Distance, limit: Self) -> Self
}
方法将给定范围限制为给定数组的有效范围:
extension Array {
public subscript (safe subRange: Range<Int>) -> ArraySlice<Element> {
let from = startIndex.advancedBy(subRange.startIndex, limit: endIndex)
let to = startIndex.advancedBy(subRange.endIndex, limit: endIndex)
return self[from ..< to]
}
}
let arr = [1,2,3,4,5]
print(arr[safe: 3..<10]) // [4, 5]
print(arr[safe: 9..<10]) // []
编辑:更新为更直接的版本
这是专门为实践而设计的。safe
命名与其他命名相同,用于清晰;请注意,它不返回nil,而是返回一个空数组用于越界索引,这在许多情况下避免了使用代码中的空检查
extension Array {
subscript(safe range: Range<Index>) -> ArraySlice<Element> {
return self[min(range.startIndex, self.endIndex)..<min(range.endIndex, self.endIndex)]
}
}
let a = [1,2,3]
a[safe: 1..<17] // [2,3]
a[safe: 4..<17] // []
a[safe: 1..<2] // [2]
扩展数组{
下标(安全范围:范围)->ArraySlice{
return self[min(range.startIndex,self.endIndex)我们可以将Martin对CollectionType
s的优秀解决方案概括如下。此外,我认为我会更喜欢像take(:range)
这样的签名,因为take(:Int)
传统上具有类似的原谅范围外语义(与集合的
下标
方法相比):
不太好。但是,除了上面更通用的代码之外,我们还可以提供一个获取(uu:Range)
替代方案:
public extension CollectionType where Index.Distance == Int {
public func take(range: Range<Int>) -> SubSequence {
let from = range.startIndex <= 0 ? startIndex : startIndex.advancedBy(range.startIndex, limit: endIndex)
let to = range.endIndex <= 0 ? startIndex : startIndex.advancedBy(range.endIndex, limit: endIndex)
return self[from..<to]
}
}
s.characters.take(3...5).array // ["d", "o", "m"]
公共扩展集合类型,其中Index.Distance==Int{
公共函数获取(范围:范围)->子序列{
let from=range.startIndex与可选集合相比,您应该更喜欢空集合。这适用于swift 4
extension Array {
/*
Safe array access via range, accounting for array bounds
examples:
[1, 2, 3][0...6] -> []
[1, 2, 3][0...1] -> [1, 2]
*/
subscript(safe range: Range<Index>) -> [Element] {
guard
range.startIndex >= self.startIndex,
range.endIndex <= self.endIndex
else {
return []
}
return Array(self[range])
}
}
扩展数组{
/*
通过范围安全访问阵列,考虑阵列边界
示例:
[1, 2, 3][0...6] -> []
[1, 2, 3][0...1] -> [1, 2]
*/
下标(安全范围:范围)->[元素]{
警卫
range.startIndex>=self.startIndex,
range.endIndex您不是在分割数组,而是在创建一个切片(即视图到原始数组中)。您打算用它做什么?是否需要子集是原始数组的一部分的副本?它只是一个Double
类型的数组,所以它是副本还是副本并不重要not@Downvoter:请让我知道这里出了什么问题,谢谢!@sketchyTech:谢谢你的编辑建议,我很感激。但是如果你想“尽可能多地生成元素”,然后——在我看来——返回a(可能为空)更有意义ArraySlice,而不是可选的ArraySlice。这纯粹是为了让它与OP的代码保持一致。我确实认为这是一个比我更好的答案,应该是可以接受的答案。请您解释一下safe关键字在这里的意义是什么!谢谢。它只是一个外部参数名。完全如@MarcusRossel所述。我们需要一些信息g区分safe
下标和常规(数组)下标否则编译器将无法推断我们是否打算对数组或我们自己的扩展使用常规下标。方法永远不会返回nil,因此可以删除?
。@sketchyTech谢谢,从nil返回开始,但认为使用nil检查而不只是使用空数组会很不方便。放弃虽然:)没问题,这是一个有趣的解决方案,但我认为Swift警察可能会因为涉及的数量复杂性而逮捕你。dropFirst
是O(n),而prefix
是O(maxLength)@sketchyTech替代版本应该做得更好。整洁的一行,看起来很棒。你可以去掉self
的两个用法,使它更紧凑……我已经自己自由地编辑了这些,
extension Array {
subscript(safe range: Range<Index>) -> ArraySlice<Element> {
return self[min(range.startIndex, self.endIndex)..<min(range.endIndex, self.endIndex)]
}
}
let a = [1,2,3]
a[safe: 1..<17] // [2,3]
a[safe: 4..<17] // []
a[safe: 1..<2] // [2]
public extension CollectionType where Index.Distance : protocol<IntegerLiteralConvertible, Comparable> {
public func take(range: Range<Index>) -> SubSequence {
let dFrom = startIndex.distanceTo(range.startIndex)
let dTo = startIndex.distanceTo(range.endIndex)
let from = dFrom <= 0 ? startIndex : startIndex.advancedBy(dFrom, limit: endIndex)
let to = dTo <= 0 ? startIndex : startIndex.advancedBy(dTo, limit: endIndex)
return self[from..<to]
}
}
public extension CollectionType {
public var array: [Generator.Element] { return Array(self) }
}
let collection = 1...5
collection.take(9...10).array // []
collection.take(1...3).array // [2, 3, 4]
collection.take((-3)...10).array // [1, 2, 3, 4, 5]
collection.take((-5)...(-2)).array // []
let s = "random string"
s.characters.take(s.startIndex.advancedBy(3)...s.startIndex.advancedBy(5)).array // ["d", "o", "m"]
public extension CollectionType where Index.Distance == Int {
public func take(range: Range<Int>) -> SubSequence {
let from = range.startIndex <= 0 ? startIndex : startIndex.advancedBy(range.startIndex, limit: endIndex)
let to = range.endIndex <= 0 ? startIndex : startIndex.advancedBy(range.endIndex, limit: endIndex)
return self[from..<to]
}
}
s.characters.take(3...5).array // ["d", "o", "m"]
extension Array {
/*
Safe array access via range, accounting for array bounds
examples:
[1, 2, 3][0...6] -> []
[1, 2, 3][0...1] -> [1, 2]
*/
subscript(safe range: Range<Index>) -> [Element] {
guard
range.startIndex >= self.startIndex,
range.endIndex <= self.endIndex
else {
return []
}
return Array(self[range])
}
}