在给定起始索引的数组中查找第一个匹配对象

时间:2018-03-14 15:59:00

标签: swift

我有一个对象数组

var arrayOfObjects: [Object]?

他们都有一个叫depth的属性。我想在该数组中找到与特定对象具有相同深度的非常下一个对象,我知道索引为:

[
   ...objects_before...,
   object_I_know: {depth:3},
   ...objects_after...
]

除了使用从object_I_know索引开始的for循环以及向下遍历直到找到它之外,是否有更有效的方法?

5 个答案:

答案 0 :(得分:3)

let nextIndex: Int? = (givenIndex ..< array.endIndex).first { index  in
    return array[index].depth == array[givenIndex].depth
}

如果有一个

,具有相同深度的对象的项目将位于该nextIndex
let nextObject: Object? = (nextIndex == nil) ? nil : array[nextIndex!]

答案 1 :(得分:0)

class Object {
    var name: String
    var depth: Float
    init(name: String, depth: Float) {
        self.name = name
        self.depth = depth
    }
}

let o1 = Object(name: "object1", depth: 10)
let o2 = Object(name: "object2", depth: 12)
let o3 = Object(name: "object3", depth: 4)
let o4 = Object(name: "object4", depth: 12)
let o5 = Object(name: "object5", depth: 14)

let array = [o1, o2, o3, o4, o5]
let knownIndex = 1
let knownDepth = array[knownIndex].depth
var searchResults = [Object]()

// iterate through the second half of the array after the known
// index and break the loop when a match is found

for i in knownIndex + 1..<array.count {
    if array[i].depth == knownDepth {
        searchResults = [array[i]]
        break
    }
}

// after the loop is finished (either by going all the way to the
// end or breaking after a match is found), check your search results

if searchResults.count > 0 {
    print("match found: \(searchResults[0].name)")
} else {
    print("no match found")
}

index(where:)也使用了一个循环,这是评论者不知道的,除了编译器在幕后为你做。 index(where:)也循环遍历整个数组,如果你已经知道起始索引(OP确实如此),那么效率不高。

答案 2 :(得分:0)

这是我提出的用于测试的示例模型:

struct S {
    let id: Int
    let depth: Int
}

var id = 0
let getID: () -> Int = { defer { id += 1 }; return id }

let objects = [
    S(id: getID(), depth: 1),
    S(id: getID(), depth: 3),
    S(id: getID(), depth: 2),
    S(id: getID(), depth: 3),
    S(id: getID(), depth: 4),
]

这是一个解决方案,它解释了没有与谓词匹配的元素的情况,或只有1个这样的元素:

let isDepth3: (S) -> Bool = { $0.depth == 3 }

// Get the index of the first item (can be nil)
let indexOfFirstDepth3 = objects.index(where: isDepth3)

// Get the index after that (can be nil), so that we can exclude everything before it
let firstIndexOfRemainingItems = indexOfFirstDepth3.flatMap { objects.index($0, offsetBy: +1, limitedBy: objects.endIndex) }
let indexOfSecondDepth3 = firstIndexOfRemainingItems.flatMap {
    // Slice the `objects` array, to omit all the items before up to and including the first depth 3 item.
    // Then find the index of the next next 3 item thereafter.
    return objects[$0...].index(where: isDepth3)
}

// Print results
func stringifyOptional<T>(_ item: T?) -> String {
    return item.map{ String(describing: $0) } ?? "nil"
}

print("First item with depth 3 is \(stringifyOptional(indexOfFirstDepth3.map{ objects[$0] })) at index \(stringifyOptional(indexOfFirstDepth3))")
print("Second item with depth 3 is \(stringifyOptional(indexOfSecondDepth3.map{ objects[$0] })) at index \(stringifyOptional(indexOfFirstDepth3))")

如果你 确定 你将拥有2个这样的元素,并且你确定强行展开是安全的,那么这可以大大简化:

let isDepth3: (S) -> Bool = { $0.depth == 3 }

let indexOfFirstDepth3 = objects.index(where: isDepth3)!
let indexOfSecondDepth3 = objects[indexOfFirstDepth3...].index(where: isDepth3)!

// Just printing the result
print("First item with depth 3 is \(objects[indexOfFirstDepth3]) at index \(indexOfFirstDepth3)")
print("Second item with depth 3 is \(objects[indexOfFirstDepth3])) at index \(indexOfFirstDepth3)")

答案 3 :(得分:0)

<强>上下文

struct DepthObject { let depth: Int }
let objs           = [a, b, c, d ,e]
let index          = 1                   //predetermined index
let depthToFind    = objs[index].depth
let startIndex     = index + 1
let remainingArray = objs[startIndex...] //The slice we want to work with

单程

let aMessage: String? = remainingArray
    .first { $0.depth == depthToFind }
    .flatMap { "The world is yours \($0)" }

根据它决定

if let nextDepthObject = remainingArray.first(where: { $0.depth == depthToFind }) {
    //Found the next one!
} else {
    //Didn't find it!
}

循环播放

var nextDepthObject: DepthObject? = nil
for sliceDepthObject in remainingArray {
    if sliceDepthObject.depth == depthToFind {
        nextDepthObject = sliceDepthObject
        break
    }
}

实施特定方法

func nextDepthObject(within array: Array<DepthObject>, startingAt index: Int) -> DepthObject? {
    guard index + 1 < array.count && index < array.count else {
        return nil
    }
    let depthToFind = array[index].depth
    let suffixArray = array[(index + 1)...]
    return suffixArray.first { $0.depth == depthToFind }
}

let theNextOne: DepthObject? = nextDepthObject(within: objs, startingAt: index)

答案 4 :(得分:0)

您可以在CollectionArray符合)上添加扩展程序:

extension Collection {
    func next(startingWith next: Self.Index, where match: (Element) -> Bool) -> Element? {
        guard next < endIndex else { return nil }
        return self[next..<endIndex].first(where: match)
    }
}

你会这样使用它:

let nextMatch = arrayOfObjects.next(startingWith: foundIndex+1) { $0.depth == searchedDepth }