在Swift中搜索一个Set

问题描述 投票:1回答:3

我有类似以下内容

struct ht : Hashable {
                       var x : Int
                       var y : Int
                       var z : Int
                       //Edit added following func following Ahmad's comment
                       var hashValue: Int { return (x+y+z) }

                       static func == (lhs: ht, rhs: ht) -> Bool
                                          {
                                            return lhs.x == rhs.x 
                                                && lhs.y == rhs.y
                                                && lhs.z == rhs.z
                                          }
                     }

let defaultX  = 4

let searchForX = 7
//let searchForX = 1000000

var ss : Set<ht> = [ ht(x:1,y:2,z:3), ht(x:4,y:5,z:6), ht(x:7, y:8, z:100), ht(x:9, y:19, z:12)]

Swift是否具有类似LINQ的功能,我可以搜索set ss以检索与searchForX = 7匹配的结构,如上所示返回(7,8,100)?如果searchForX = 1000000我希望它返回(4,5,6),所以故障转移返回defaultX = 4的值

我当前的代码使用循环。在C#中,您可以使用LINQ并指定.FirstOrDefault(...)。

这在Swift中可能吗?

谢谢

swift
3个回答
0
投票

Swift不是我真正的东西,但是类似于下面代码的三元运算符可能会让你感动。

var answer = ss.first(where: { $0.x == searchForX }) ?? ss.first(where: { $0.x == defaultX })

问候

麦克风


0
投票

所以你的问题的快速答案是

let element = ss.first { $0.x == searchForX } ?? ss.first { $0.x == defaultX }

这可以变成一个简单的扩展

extension Sequence {

    func first(_ criteria: (Element) -> Bool, orDefault: (Element) -> Bool) -> Element? {
        return first(where: criteria) ?? first(where: orDefault)
    }

}

let element = ss.first({ $0.x == searchForX }, orDefault: { $0.x == searchForX })

通过使它成为Sequence的扩展,它将适用于Arrays和任何实现Sequence的东西。


如果您担心性能,可以自己动手。

extension Sequence {

    func first(_ criteria: (Element) -> Bool, orDefault: (Element) -> Bool) -> Element? {
        var defaultElement: Element?
        for element in self {
            if criteria(element) { return element }
            if criteria(element) { defaultElement = element }
        }
        return defaultElement
    }

}

0
投票

您可以实现自己的自定义方法来执行所需的功能。

首先,如果你要声明一组自定义结构,请注意你的结构必须是Hashable协议 - 这意味着它必须是Equatable - ,因此它将实现如下:

struct MyStruct: Hashable, Equatable {
    var x : Int
    var y : Int
    var z : Int

    // Hashable
    var hashValue: Int

    // Equatable
    static func ==(lhs: MyStruct, rhs: MyStruct) -> Bool {
        return lhs.x == rhs.x
    }
}

所以,你可以声明一组MyStruct

可能这不是为hashValue分配值的正确方法,但为了回答问题,我将为它们分配虚拟值。

为了实现实现所需输出的方法,我建议在set扩展中声明它(如果你让它也适用于数组,你可以将它声明为Collection扩展),受set元素类型的约束:

extension Set where Element == MyStruct {
    func firstOrDefault(for expectedXValue: Int, defaultXValue: Int) -> MyStruct? {

        // expeccted
        if let expected = first(where: { $0.x == expectedXValue }) {
            return expected
        }

        // default
        if let defaultValue = first(where: { $0.x == defaultXValue }) {
            return defaultValue
        }

        // neither
        return nil
    }
}

请注意,如果集合中有多个预期或默认x值,它将返回第一个匹配的值。

您会注意到实现firstOrDefault方法的主要功能是使用first(where:)方法(类似于您要查找的内容),并使用一些逻辑来获取-first-default值。


输出:

如果有一个x = 7的预期对象:

let mySet: Set<MyStruct> = [MyStruct(x: 1, y: 2, z: 3, hashValue: 101),
                            MyStruct(x: 4, y: 5, z: 6, hashValue: 102),
                            MyStruct(x: 7, y: 8, z: 100, hashValue: 103),
                            MyStruct(x: 9, y: 19, z: 12, hashValue: 104)]

let myObject = mySet.firstOrDefault(for: 7, defaultXValue: 4)
dump(myObject)

/*
 ▿ Optional(__lldb_expr_187.MyStruct(x: 7, y: 8, z: 9, hashValue: 102))
 ▿ some: __lldb_expr_187.MyStruct
 - x: 7
 - y: 8
 - z: 9
 - hashValue: 102
 */

如果没有预期值且默认值为x = 4:

let mySet2: Set<MyStruct> = [MyStruct(x: 1, y: 2, z: 3, hashValue: 101),
                            MyStruct(x: 4, y: 5, z: 6, hashValue: 102),
                            MyStruct(x: 1000, y: 8, z: 100, hashValue: 103),
                            MyStruct(x: 9, y: 19, z: 12, hashValue: 104)]

let myObject2 = mySet2.firstOrDefault(for: 7, defaultXValue: 4)
dump(myObject2)

/*
 ▿ Optional(__lldb_expr_249.MyStruct(x: 4, y: 5, z: 6, hashValue: 102))
 ▿ some: __lldb_expr_249.MyStruct
 - x: 4
 - y: 5
 - z: 6
 - hashValue: 102
 */

如果没有预期值且没有默认值:

let mySet3: Set<MyStruct> = [MyStruct(x: 1, y: 2, z: 3, hashValue: 101),
                             MyStruct(x: 1000, y: 5, z: 6, hashValue: 102),
                             MyStruct(x: 1000, y: 8, z: 100, hashValue: 103),
                             MyStruct(x: 9, y: 19, z: 12, hashValue: 104)]

let myObject3 = mySet3.firstOrDefault(for: 7, defaultXValue: 4)
dump(myObject3) // - nil
© www.soinside.com 2019 - 2024. All rights reserved.