Ruby 范围(Range)
范围是Ruby中一个独特而强大的特性,用于表示一个连续的值序列。范围可以包含数字、字母甚至更复杂的对象。Ruby范围功能丰富,支持多种操作和迭代方式。本章将详细介绍Ruby中范围的创建、操作和使用方法。
🎯 范围基础
范围定义
Ruby提供了两种方式来创建范围:
ruby
# 包含结束值的范围(..)
inclusive_range = 1..5
puts inclusive_range # 1..5
puts inclusive_range.include?(5) # true
# 不包含结束值的范围(...)
exclusive_range = 1...5
puts exclusive_range # 1...5
puts exclusive_range.include?(5) # false
# 字符范围
letter_range = 'a'..'e'
puts letter_range # "a".."e"
puts letter_range.include?('e') # true
# 字符串范围
word_range = 'aa'..'az'
puts word_range # "aa".."az"
# 日期范围
require 'date'
date_range = Date.new(2023, 12, 25)..Date.new(2023, 12, 31)
puts date_range # 2023-12-25..2023-12-31范围创建方法
ruby
# 使用字面量语法(推荐)
range1 = 1..10
range2 = 'a'..'z'
# 使用Range.new方法
range3 = Range.new(1, 10)
range4 = Range.new('a', 'z')
range5 = Range.new(1, 10, true) # 第三个参数为true表示排除结束值
puts range1 == range3 # true
puts range2 == range4 # true
puts range5 # 1...10📏 范围属性
范围基本属性
ruby
range = 1..10
# 获取范围的开始和结束值
puts range.begin # 1
puts range.first # 1 (begin的别名)
puts range.end # 10
puts range.last # 10 (end的别名)
# 检查是否排除结束值
puts range.exclude_end? # false
puts (1...10).exclude_end? # true
# 范围长度
puts range.size # 10
# 检查范围是否为空
puts range.empty? # false
puts (5..3).empty? # true (无效范围)
# 转换为数组
array = range.to_a
puts array.inspect # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]范围比较
ruby
range1 = 1..5
range2 = 1..5
range3 = 2..6
# 相等性比较
puts range1 == range2 # true
puts range1 == range3 # false
# 范围包含关系
puts range1.cover?(3) # true
puts range1.cover?(6) # false
puts range1.include?(3) # true
puts range1.include?(6) # false
# 使用===操作符(case语句中使用)
puts range1 === 3 # true
puts range1 === 6 # false
# 范围覆盖检查
range_a = 1..10
range_b = 3..7
range_c = 8..15
puts range_a.cover?(range_b) # true (range_a包含range_b)
puts range_a.cover?(range_c) # false🔍 范围操作
范围成员检查
ruby
numbers = 1..100
# 检查单个值
puts numbers.include?(50) # true
puts numbers.include?(150) # false
# 使用cover?方法(更高效)
puts numbers.cover?(50) # true
puts numbers.cover?(150) # false
# 检查另一个范围
small_range = 25..75
puts numbers.cover?(small_range) # true
# 字符范围检查
letters = 'a'..'z'
puts letters.include?('m') # true
puts letters.include?('A') # false
# 字符串范围检查
words = 'aa'..'zz'
puts words.include?('ab') # true
puts words.include?('ba') # true
puts words.include?('aaa') # false (超出范围)范围边界操作
ruby
range = 10..20
# 获取范围的最小值和最大值
puts range.min # 10
puts range.max # 20
# 获取前几个元素
puts range.first(3).inspect # [10, 11, 12]
# 获取后几个元素
puts range.last(3).inspect # [18, 19, 20]
# 获取范围的中间值
def range_median(range)
min, max = range.minmax
(min + max) / 2.0
end
puts range_median(range) # 15.0
# 范围的统计信息
def range_stats(range)
{
min: range.min,
max: range.max,
size: range.size,
average: (range.min + range.max) / 2.0
}
end
stats = range_stats(1..100)
puts stats # {:min=>1, :max=>100, :size=>100, :average=>50.5}🔁 范围迭代
基本迭代
ruby
# 数字范围迭代
(1..5).each { |n| print "#{n} " }
puts # 1 2 3 4 5
# 字符范围迭代
('a'..'e').each { |char| print "#{char} " }
puts # a b c d e
# 使用each_with_index
('x'..'z').each_with_index do |char, index|
puts "#{index}: #{char}"
end
# 0: x
# 1: y
# 2: z
# 反向迭代
(1..5).reverse_each { |n| print "#{n} " }
puts # 5 4 3 2 1高级迭代
ruby
# 使用map转换
squared = (1..5).map { |n| n ** 2 }
puts squared.inspect # [1, 4, 9, 16, 25]
# 使用select筛选
evens = (1..10).select(&:even?)
puts evens.inspect # [2, 4, 6, 8, 10]
# 使用reject排除
odds = (1..10).reject(&:even?)
puts odds.inspect # [1, 2, 3, 5, 7, 9]
# 使用find查找
first_large = (1..100).find { |n| n > 50 }
puts first_large # 51
# 使用take和drop
range = 1..20
puts range.take(5).inspect # [1, 2, 3, 4, 5]
puts range.drop(15).inspect # [16, 17, 18, 19, 20]分块迭代
ruby
# 使用each_slice分块处理
(1..20).each_slice(5) do |slice|
puts slice.inspect
end
# [1, 2, 3, 4, 5]
# [6, 7, 8, 9, 10]
# [11, 12, 13, 14, 15]
# [16, 17, 18, 19, 20]
# 使用each_cons连续处理
(1..10).each_cons(3) do |cons|
puts cons.inspect
end
# [1, 2, 3]
# [2, 3, 4]
# [3, 4, 5]
# [4, 5, 6]
# [5, 6, 7]
# [6, 7, 8]
# [7, 8, 9]
# [8, 9, 10]
# 使用cycle无限循环
# (1..3).cycle(2) { |n| print "#{n} " }
# puts # 1 2 3 1 2 3🎯 范围实践示例
数字范围应用
ruby
class NumberRangeUtils
# 检查数字是否在有效范围内
def self.valid_range?(number, min, max)
(min..max).cover?(number)
end
# 生成指定范围内的随机数
def self.random_in_range(range)
range.to_a.sample
end
# 计算范围内的质数
def self.primes_in_range(range)
range.select { |n| prime?(n) }
end
# 计算范围内数字的和
def self.sum_range(range)
# 对于大范围,使用数学公式更高效
if range.exclude_end?
n = range.last - range.first
else
n = range.last - range.first + 1
end
n * (range.first + range.last) / 2
end
private
def self.prime?(n)
return false if n < 2
return true if n == 2
return false if n.even?
(3..Math.sqrt(n)).step(2) do |i|
return false if n % i == 0
end
true
end
end
# 使用数字范围工具
puts NumberRangeUtils.valid_range?(15, 10, 20) # true
puts NumberRangeUtils.valid_range?(25, 10, 20) # false
random_number = NumberRangeUtils.random_in_range(1..100)
puts "随机数: #{random_number}"
primes = NumberRangeUtils.primes_in_range(1..30)
puts "1到30的质数: #{primes.inspect}" # [2, 3, 5, 7, 11, 13, 17, 19, 23, 29]
sum = NumberRangeUtils.sum_range(1..100)
puts "1到100的和: #{sum}" # 5050字符范围应用
ruby
class CharacterRangeUtils
# 生成字母表
def self.alphabet
('a'..'z').to_a
end
# 生成大写字母表
def self.uppercase_alphabet
('A'..'Z').to_a
end
# 检查字符是否为字母
def self.letter?(char)
('a'..'z').cover?(char.downcase)
end
# 检查字符是否为数字
def self.digit?(char)
('0'..'9').cover?(char)
end
# 生成随机字母
def self.random_letter
('a'..'z').to_a.sample
end
# 生成指定范围内的随机字符串
def self.random_string(length, char_range = 'a'..'z')
Array.new(length) { char_range.to_a.sample }.join
end
# 字符串范围检查
def self.in_range?(string, start_str, end_str)
(start_str..end_str).cover?(string)
end
end
# 使用字符范围工具
puts "字母表: #{CharacterRangeUtils.alphabet.take(5).inspect}" # ["a", "b", "c", "d", "e"]
puts "大写字母: #{CharacterRangeUtils.uppercase_alphabet.take(5).inspect}" # ["A", "B", "C", "D", "E"]
puts CharacterRangeUtils.letter?('A') # true
puts CharacterRangeUtils.digit?('5') # true
random_letter = CharacterRangeUtils.random_letter
puts "随机字母: #{random_letter}"
random_string = CharacterRangeUtils.random_string(8)
puts "随机字符串: #{random_string}"
puts CharacterRangeUtils.in_range?("apple", "a", "z") # true日期范围应用
ruby
require 'date'
class DateRangeUtils
# 创建日期范围
def self.date_range(start_date, end_date)
Date.parse(start_date)..Date.parse(end_date)
end
# 计算日期范围内的天数
def self.days_in_range(date_range)
(date_range.end - date_range.begin).to_i + 1
end
# 获取工作日数量
def self.business_days(date_range)
count = 0
date_range.each { |date| count += 1 unless date.saturday? || date.sunday? }
count
end
# 获取周末天数
def self.weekend_days(date_range)
count = 0
date_range.each { |date| count += 1 if date.saturday? || date.sunday? }
count
end
# 按周分组
def self.group_by_week(date_range)
weeks = Hash.new { |h, k| h[k] = [] }
date_range.each do |date|
week_number = date.cweek
weeks[week_number] << date
end
weeks
end
# 获取特定星期几的日期
def self.days_of_week(date_range, weekday)
# 0 = 星期日, 1 = 星期一, ..., 6 = 星期六
date_range.select { |date| date.wday == weekday }
end
end
# 使用日期范围工具
date_range = DateRangeUtils.date_range("2023-12-01", "2023-12-31")
puts "12月天数: #{DateRangeUtils.days_in_range(date_range)}" # 31
business_days = DateRangeUtils.business_days(date_range)
puts "工作日: #{business_days}"
weekend_days = DateRangeUtils.weekend_days(date_range)
puts "周末: #{weekend_days}"
mondays = DateRangeUtils.days_of_week(date_range, 1)
puts "12月的星期一: #{mondays.inspect}"🔧 范围与其他数据结构
范围与数组
ruby
# 范围转换为数组
numbers = (1..10).to_a
puts numbers.inspect # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 数组转换为范围(如果可能)
def array_to_range(arr)
return nil if arr.empty?
min, max = arr.minmax
(min..max) if (min..max).to_a == arr.sort
end
consecutive = [1, 2, 3, 4, 5]
puts array_to_range(consecutive) # 1..5
non_consecutive = [1, 3, 5, 7]
puts array_to_range(non_consecutive) # nil
# 范围与数组操作
range = 1..10
array = [5, 15, 25, 35]
# 检查数组元素是否在范围内
in_range = array.select { |n| range.cover?(n) }
puts in_range.inspect # [5]
# 找出范围外的数组元素
out_of_range = array.reject { |n| range.cover?(n) }
puts out_of_range.inspect # [15, 25, 35]范围与哈希
ruby
# 使用范围作为哈希键
grade_ranges = {
90..100 => "A",
80...90 => "B",
70...80 => "C",
60...70 => "D",
0...60 => "F"
}
def get_grade(score, grade_ranges)
grade_ranges.each do |range, grade|
return grade if range.cover?(score)
end
"Invalid"
end
puts get_grade(95, grade_ranges) # A
puts get_grade(85, grade_ranges) # B
puts get_grade(75, grade_ranges) # C
puts get_grade(65, grade_ranges) # D
puts get_grade(55, grade_ranges) # F
# 范围分组数据
scores = [95, 87, 76, 92, 88, 73, 91, 85, 79, 94]
score_groups = scores.group_by do |score|
case score
when 90..100 then "优秀"
when 80...90 then "良好"
when 70...80 then "中等"
when 60...70 then "及格"
else "不及格"
end
end
puts score_groups
# {"优秀"=>[95, 92, 91, 94], "良好"=>[87, 88, 85], "中等"=>[76, 73, 79]}📊 范围性能优化
大范围处理
ruby
# 对于大范围,避免转换为数组
# 低效方式
# sum = (1..1_000_000).to_a.sum
# 高效方式
def sum_range_efficiently(range)
first, last = range.first, range.last
count = last - first + 1
count * (first + last) / 2
end
large_sum = sum_range_efficiently(1..1_000_000)
puts "大范围和: #{large_sum}" # 500000500000
# 使用lazy延迟计算
def process_large_range(range)
range.lazy
.select(&:even?)
.map { |n| n ** 2 }
.first(10)
.to_a
end
result = process_large_range(1..1_000_000)
puts result.inspect # [4, 16, 36, 64, 100, 144, 196, 256, 324, 400]范围搜索优化
ruby
# 使用bsearch进行二分搜索(需要排序的范围)
sorted_array = (1..1000).to_a
# 查找第一个大于等于500的元素
index = sorted_array.bsearch_index { |x| x >= 500 }
puts "索引: #{index}, 值: #{sorted_array[index]}" # 索引: 499, 值: 500
# 查找最后一个小于等于500的元素
index = sorted_array.bsearch_index { |x| x > 500 }&.pred || (sorted_array.length - 1)
puts "索引: #{index}, 值: #{sorted_array[index]}" # 索引: 499, 值: 500
# 范围内的高效搜索
class RangeSearch
def self.binary_search(range, target)
return false unless range.cover?(target)
low, high = range.first, range.last
while low <= high
mid = (low + high) / 2
return true if mid == target
if mid < target
low = mid + 1
else
high = mid - 1
end
end
false
end
end
puts RangeSearch.binary_search(1..1000, 500) # true
puts RangeSearch.binary_search(1..1000, 1500) # false🎯 范围最佳实践
1. 选择合适的范围类型
ruby
# 包含结束值的范围(用于大多数情况)
inclusive_range = 1..10
puts inclusive_range.to_a # [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]
# 不包含结束值的范围(用于数组索引等)
exclusive_range = 0...10
puts exclusive_range.to_a # [0, 1, 2, 3, 4, 5, 6, 7, 8, 9]
# 在循环中使用
array = ['a', 'b', 'c', 'd', 'e']
(0...array.length).each { |i| puts "#{i}: #{array[i]}" }
# 在case语句中使用
def grade_letter(score)
case score
when 90..100 then 'A'
when 80...90 then 'B'
when 70...80 then 'C'
when 60...70 then 'D'
else 'F'
end
end
puts grade_letter(95) # A
puts grade_letter(85) # B2. 安全处理范围
ruby
class SafeRangeHandler
# 安全创建范围
def self.safe_range(start_val, end_val, exclude_end = false)
return nil if start_val.nil? || end_val.nil?
return nil if start_val > end_val
exclude_end ? (start_val...end_val) : (start_val..end_val)
end
# 安全范围迭代
def self.safe_each(range, &block)
return [] unless range.is_a?(Range)
return [] if range.empty?
range.each(&block) if block_given?
range.to_a
end
# 范围边界验证
def self.validate_range(range, min_bound, max_bound)
return false unless range.is_a?(Range)
range.begin >= min_bound && range.end <= max_bound
end
end
# 使用安全范围处理
safe_range = SafeRangeHandler.safe_range(1, 10)
puts safe_range # 1..10
invalid_range = SafeRangeHandler.safe_range(10, 1)
puts invalid_range # nil
SafeRangeHandler.safe_each(1..5) { |n| puts "数字: #{n}" }
valid = SafeRangeHandler.validate_range(1..10, 0, 100)
puts "范围有效: #{valid}" # 范围有效: true3. 范围性能优化
ruby
class RangePerformance
# 高效的范围求和
def self.sum_range(range)
# 使用数学公式而不是迭代
n = range.size
first, last = range.first, range.last
n * (first + last) / 2
end
# 高效的范围平均值
def self.average_range(range)
(range.first + range.last) / 2.0
end
# 高效的范围中位数
def self.median_range(range)
min, max = range.minmax
(min + max) / 2.0
end
# 范围内查找(使用cover?而不是include?)
def self.fast_contains?(range, value)
range.cover?(value)
end
end
# 使用性能优化的范围操作
large_range = 1..1_000_000
puts "和: #{RangePerformance.sum_range(large_range)}" # 500000500000
puts "平均值: #{RangePerformance.average_range(large_range)}" # 500000.5
puts "中位数: #{RangePerformance.median_range(large_range)}" # 500000.5
puts RangePerformance.fast_contains?(1..100, 50) # true4. 范围在实际应用中的使用
ruby
# 密码强度检查
class PasswordStrengthChecker
def self.check_length(password, min_length = 8, max_length = 128)
valid_length = (min_length..max_length).cover?(password.length)
{
valid: valid_length,
message: valid_length ? "长度合适" : "密码长度应在#{min_length}-#{max_length}字符之间"
}
end
def self.check_character_variety(password)
has_lower = password.match?(/[a-z]/)
has_upper = password.match?(/[A-Z]/)
has_digit = password.match?(/\d/)
has_special = password.match?(/[!@#$%^&*(),.?":{}|<>]/)
variety_score = [has_lower, has_upper, has_digit, has_special].count(true)
{
score: variety_score,
details: {
lowercase: has_lower,
uppercase: has_upper,
digits: has_digit,
special: has_special
}
}
end
end
# 使用密码强度检查
password = "MyPassword123!"
length_check = PasswordStrengthChecker.check_length(password)
puts length_check # {:valid=>true, :message=>"长度合适"}
variety_check = PasswordStrengthChecker.check_character_variety(password)
puts variety_check # {:score=>4, :details=>{:lowercase=>true, :uppercase=>true, :digits=>true, :special=>true}}
# 年龄验证
class AgeValidator
def self.valid_age?(age)
(0..150).cover?(age)
end
def self.age_group(age)
case age
when 0..2 then "婴儿"
when 3..12 then "儿童"
when 13..17 then "青少年"
when 18..59 then "成年人"
when 60..150 then "老年人"
else "无效年龄"
end
end
end
puts AgeValidator.valid_age?(25) # true
puts AgeValidator.age_group(25) # 成年人📚 下一步学习
掌握了Ruby范围操作后,建议继续学习:
- Ruby 迭代器 - 深入学习迭代模式
- Ruby 文件处理及I/O - 了解文件读写操作
- Ruby 异常处理 - 掌握错误处理机制
- Ruby 面向对象 - 深入理解面向对象编程
继续您的Ruby学习之旅吧!