我有类似以下内容
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不是我真正的东西,但是类似于下面代码的三元运算符可能会让你感动。
var answer = ss.first(where: { $0.x == searchForX }) ?? ss.first(where: { $0.x == defaultX })
问候
麦克风
所以你的问题的快速答案是
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
的扩展,它将适用于Array
s和任何实现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
}
}
您可以实现自己的自定义方法来执行所需的功能。
首先,如果你要声明一组自定义结构,请注意你的结构必须是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