Определите, содержит ли диапазон значение
Я пытаюсь найти способ определить, попадает ли значение в Range
в Swift.
В основном то, что я пытаюсь сделать, это адаптировать один из примеров инструкции switch, чтобы сделать что-то вроде этого:
let point = (1, -1)
switch point {
case let (x, y) where (0..5).contains(x):
println("(\(x), \(y)) has an x val between 0 and 5.")
default:
println("This point has an x val outside 0 and 5.")
}
Насколько я могу судить, нет никакого встроенного способа сделать то, что делает мой воображаемый метод .contains
.
Итак, я попытался расширить класс Range
. Однако я столкнулся с проблемами с дженериками. Я не могу расширить Range<Int>
, поэтому мне пришлось попытаться расширить Range
.
Ближайшим я получил это, но он не работает, поскольку >=
и <=
не определены для ForwardIndex
extension Range {
func contains(val:ForwardIndex) -> Bool {
return val >= self.startIndex && val <= self.endIndex
}
}
Как мне добавить метод .contains
в Range
? Или есть лучший способ определить, попадает ли значение в диапазон?
Edit2: Это, похоже, работает для расширения Range
extension Range {
func contains(val:T) -> Bool {
for x in self {
if(x == val) {
return true
}
}
return false
}
}
var a = 0..5
a.contains(3) // true
a.contains(6) // false
a.contains(-5) // false
Меня очень интересует оператор ~ =, упомянутый ниже; глядя на это сейчас.
Ответы
Ответ 1
Вы можете сделать это с помощью оператора ~=
:
let point = (1, -1)
switch point {
case let (x, y) where (0..5) ~= x:
println("(\(x), \(y)) has an x val between 0 and 5.")
default:
println("This point has an x val outside 0 and 5.")
}
Вы также можете сделать это непосредственно в коммутаторе:
let point = (1, -1)
let (x, y) = point
switch x {
case 0..5:
println("yes")
default:
println("no")
}
~=
- оператор совпадения шаблонов, используемый операторами case. Подробнее см. в документах.
Ответ 2
В Swift 5, в соответствии с вашими потребностями, вы можете выбрать один из следующих вариантов, чтобы определить, содержит ли Range
(или ClosedRange
) значение.
1. contains(_:)
метод
Range
, ClosedRange
, CountableRange
и CountableClosedRange
есть contains(_:)
метод. Range
contains(_:)
метод имеет следующее объявление:
func contains(_ element: Bound) -> Bool
Возвращает логическое значение, указывающее, содержится ли данный элемент в диапазоне.
Использование:
let value: Int = 0
let range = -200 ..< 300
print(range.contains(value)) // prints true
2. ~=(_:_:)
оператор
Range
, ClosedRange
, CountableRange
и CountableClosedRange
имеют ~=(_:_:)
оператор. Оператор Range
~=(_:_:)
имеет следующее объявление:
static func ~=(Range<Bound>, Bound)
Возвращает логическое значение, указывающее, включено ли значение в диапазон.
Использование:
let value = 0
let range = -200 ..< 300
print(range ~= value) // prints true
3. Смена оператора
Простой способ проверить, если Range
, ClosedRange
, CountableRange
или CountableClosedRange
содержит значение использовать переключатель выражение:
let value = 0
switch value {
case -200 ..< 300:
print("OK") // prints "OK"
default:
break
}
4. Сравнение с шаблоном if case
В качестве альтернативы предыдущему оператору switch вы можете использовать if case
:
let value = 0
if case -200 ..< 300 = value {
print("OK") // prints "OK"
}
Поэтому, чтобы решить вашу проблему, вы можете использовать один из следующих вариантов:
let point = (1, -1)
switch point {
case let (x, y) where (0 ..< 5).contains(x):
print("(\(x), \(y)) has an x val between 0 and 5.")
default:
print("This point has an x val outside 0 and 5.")
}
let point = (1, -1)
if case let (x, y) = point, 0 ..< 5 ~= x {
print("(\(x), \(y)) has an x val between 0 and 5.")
}
Ответ 3
Вместо того, чтобы возиться с Range, вы можете добавить простую вспомогательную функцию, подобную этой
let point = (1, -1)
switch point {
case let (x, y) where contains((0..5),x):
println("(\(x), \(y)) has an x val between 0 and 5.")
default:
println("This point has an x val outside 0 and 5.")
}
func contains(range :Range<Int>, x: Int)->Bool{
for num in range{
if(num==x){
return true
}
}
return false
}
Возможно, вы также можете сделать что-то подобное с закрытием.
Ответ 4
Если вы хотите написать расширение contains
Range
, используйте distanceTo
для ForwardIndex
, чтобы определить, попадает ли заданное значение в диапазон.
Также используйте специальный тип Element
вместо общего протокола FowardIndex
как тип параметра.
Оба distanceTo
и Element
являются частью определения Range
.
extension Range {
func contains(element: Element) -> Bool {
return startIndex.distanceTo(element) >= 0 && element.distanceTo(endIndex) > 0
}
}
Плюс Range
уже имеет метод contains
от extension SequenceType where Generator.Element : Equatable
. Таким образом, вы можете просто использовать его, не набирая его самостоятельно.
Ответ 5
Я смотрел на то же самое и делал:
let r = 7...9
operator infix ~ {}
func ~ (range:Range<Int>, item:Int) -> Bool{
return item >= range.startIndex && item <= range.endIndex - 1
}
r ~ 9
тогда я увидел, что ~ = делает то же самое!