【问题标题】:swift range greater than lower bound快速范围大于下限
【发布时间】:2017-05-17 05:03:07
【问题描述】:

我需要像这样实现经验过滤器

  • 0 到 2 年
  • 2 至 4 年

如何快速表达?

问题是我不能表达超过 2 到 4 年。虽然我可以做的少于上限。例如像这样

let underTen = 0.0..<10.0

我需要这样的东西(大于下限)

let uptoTwo = 0.0...2.0
let twoPlus = 2.0>..4.0  // compiler error

目前我正在做

let twoPlus = 2.1...4.0

但这并不完美。

【问题讨论】:

  • 你在使用 Ints 吗?
  • @WarifAkhandRishi 你的问题和你的例子相互矛盾。您的问题要求对“0 到 2”(包括 2)和“2+ 到 4”的范围进行分段,但您的示例显示“0 到,不包括 2”和“2+ 到 4”
  • 你如何使用这两个范围?如果您使用0.0...2.02.0...4.0,那么如果您检查第一个范围,然后检查第二个范围,它将按需要工作。如果值为 2.0,它将被第一个范围捕获。这意味着只有超过 2.0 的值才会被第二个范围捕获。
  • Warif:不是加 0.1,而是加 Double.ulp 它尽可能接近 2.0,而不是 2.0
  • switch years { case 0...2: print(true) case 2...4: print(true) }

标签: swift swift3 nsrange


【解决方案1】:

nextUp 来自 FloatingPoint 协议

您可以使用DoublenextUp 属性,如FloatingPoint protocol 中的蓝图,Double 符合

下一个

比较大于此值的最小可表示值。

对于任何有限值xx.nextUp 大于x。 ...

即:

let uptoTwo = 0.0...2.0
let twoPlus = 2.0.nextUp...4.0

ulp 属性也被蓝图在FloatingPoint 协议中,已在您的问题的 cmets 中提及。对于大多数数字,这是self 和下一个更大的可表示数字之间的差:

ulp

self最后一个位置的单位。

这是有效位中最低有效位的单位 self。对于大多数数字x,这是x 和 下一个更大(数量级)的可表示数字。 ...

nextUp 本质上是返回self 的值加上ulp。因此,对于您上面的示例,以下是等效的(而在此用例中应该首选 imo,nextup)。

let uptoTwo = 0.0...2.0 
let twoPlus = (2.0+2.0.ulp)...4.0

您可能还想考虑将twoPlus 中的下限文字替换为前面uptoTwo 范围的upperBound 属性:

let uptoTwo = 0.0...2.0                       // [0, 2] closed-closed
let twoPlus = uptoTwo.upperBound.nextUp...4.0 // (2, 4] open-closed

if uptoTwo.overlaps(twoPlus) {
    print("the two ranges overlap ...")
}
else {
    print("ranges are non-overlapping, ok!")
}
// ranges are non-overlapping, ok!

【讨论】:

  • @sketchyTech 我很欣赏编辑,但定义一个新的自定义运算符(如这个)存在(语义)问题。在 Swift 3 中,Range 类型被明确描述为从下限定义半开区间(例如使用半开运算符 ..&lt;)并且不包括上限 .另一方面,ClosedRange 被描述为一个封闭区间,包括它的下限和上限。您上面的运算符构造了一个ClosedRange 实例,但可能会造成混淆,因为它不包括构造闭合区间时给出的下限,...
  • ... 与我们在实例化 ClosedRange 类型的实例时所期望的相反。如果我们真的要添加一个新的半开运算符(不包括下限),我们应该为了语义,还创建一个新的 Range 类型,涵盖这种特殊的半开情况(我们不太喜欢这样做,尽管)。因此,我将恢复您的编辑(这一次;仍然非常感谢,我的许多/大部分答案总是可以改进的!),但您可以随意使用自定义运算符添加您自己的答案。
【解决方案2】:

您可以创建一种方法来识别高于下限的值,而不是创建一种新的范围类型:

extension ClosedRange {
    func containsAboveLowerBound(value:Bound) -> Bool {
        if value > self.lowerBound {
            return self.contains(value)
        }
        else {
            return false
        }
    }
}

像这样实现它:

let r = 2.0...3.0
r.containsAboveLowerBound(value: 2.0) // false
r.containsAboveLowerBound(value: 2.01) // true

【讨论】:

  • 有效答案+1。寻找更简单的解决方案。
【解决方案3】:

如果您的实际目的是使用 ranges 进行过滤,那么将它们设为闭包怎么样?

let underTen = {0.0 <= $0 && $0 < 10.0}
let upToTwo = {0.0 <= $0 && $0 <= 2.0}
let twoPlus = {2.0 <  $0 && $0 <= 4.0}

你可以像这样使用这样的过滤闭包

class Client: CustomStringConvertible {
    var experience: Double
    init(experience: Double) {self.experience = experience}
    var description: String {return "Client(\(experience))"}
}
let clients = [Client(experience: 1.0),Client(experience: 2.0),Client(experience: 3.0)]
let filteredUnderTen = clients.filter {underTen($0.experience)}
print(filteredUnderTen) //->[Client(1.0), Client(2.0), Client(3.0)]
let filteredUpToTwo = clients.filter {upToTwo($0.experience)}
print(filteredUpToTwo) //->[Client(1.0), Client(2.0)]
let filteredTwoPlus = clients.filter {twoPlus($0.experience)}
print(filteredTwoPlus) //->[Client(3.0)]

【讨论】:

  • 我没有用它来解决这个问题。但我将来会在其他类型的情况下使用它。向我展示了一些新的东西,谢谢。
【解决方案4】:

我认为这样做,

extension ClosedRange where Bound == Int {
    func containsExclusiveOfBounds(_ bound: Bound) -> Bool {
        return !(bound == lowerBound || bound == upperBound)
    }
}

【讨论】:

    猜你喜欢
    • 2016-06-12
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-12-10
    • 1970-01-01
    • 2010-11-14
    相关资源
    最近更新 更多