Python内快捷高效的Interval处理模块——portion库文档

安装

pip install portiongithub官网

使用文档

新建Interval对象

一般对象

import portion as P
>>> P.open(1, 2) # 全开
(1,2)
>>> P.closed(1, 2) # 全闭
[1,2]
>>> P.openclosed(1, 2)
(1,2]
>>> P.closedopen(1, 2)
[1,2)
>>> P.singleton(1)
[1]
>>> P.empty()
()

进阶对象

import portion as P
>>> P.closed('a', 'z') # 支持可比的值,如字符、日期等
['a','z']
>>> import datetime
>>> P.closed(datetime.date(2011, 3, 15), datetime.date(2013, 10, 10))
[datetime.date(2011, 3, 15),datetime.date(2013, 10, 10)]
>>> P.openclosed(-P.inf, 0) # 支持无穷大&无穷小
(-inf,0]

对象合并(会自动得到结果)

import portion as P
>>> (P.open(10, 11) | P.closed(0, 1) | P.closed(20, 21))[0] # 可使用 ' | ' 来将多个Interval对象合并,并支持index访问
[0,1]
>>> P.empty() | P.closed(0, 1)
[0,1]
>>> P.closed(1, 2) | P.closed(2, 3) | P.closed(4, 5)
[1,3] | [4,5]

Interval边界和属性

import portion as P

# empty属性
>>> P.closed(0, 0).empty # 当且仅当Interval全空是才成立
False
>>> P.openclosed(0, 0).empty
True
>>> P.empty().empty
True

# atomic属性
>>> (P.closed(0, 1) | P.closed(1, 2)).atomic # 当Interval对象仅有一个区间时才为True
True
>>> (P.closed(0, 1) | P.closed(2, 3)).atomic
False

# enclosure属性
>>> (P.closed(0, 1) | P.open(2, 3)).enclosure # 同时包含Interval对象所有区间的最小独立区间
[0,3)
# left, right, lower, upper属性
>> P.CLOSED, P.OPEN
CLOSED, OPEN
>>> x = P.closedopen(0, 1)
>>> x.left, x.lower, x.upper, x.right # 分别代表开闭与否、上下界数值(当非atomic时,上述数值以enclosure属性为准)
(CLOSED, 0, 1, OPEN)

Interval操作方法

import portion as P

# i.intersection(other)方法和 i & other,返回两个Interval对象的交集
>>> P.closed(0, 2) & P.closed(1, 3)
[1,2]

# i.union(other)方法和 i | other,返回两个Interval对象的并集
>>> P.closed(0, 1) | P.closed(2, 3)
[0,1] | [2,3]

# i.complement(other)方法和 ~i,返回两个Interval对象的补集
>>> ~P.closed(0, 1)
(-inf,0) | (1,+inf)
>>> ~(P.open(-P.inf, 0) | P.open(1, P.inf))
[0,1]

# i.difference(other)方法和 i - other,返回两个Interval对象的差集
>>> P.closed(0, 4) - P.closed(1, 2)
[0,1) | (2,4]

# i.contains(other)方法和 other in i,判断给定值或Interval是否位于当前Interval内
>>> 2 in P.open(0, 2)
False
>>> P.open(0, 1) in P.closed(0, 2)
True

# i.adjacent(other)方法,判断2个Interval是否彼此紧邻(可组合为atomic的Interval对象)
>>> P.closed(0, 1).adjacent(P.openclosed(1, 2))
True
>>> P.closed(0, 1).adjacent(P.closed(1, 2))
False

# i.overlaps(other)方法,判断2个Interval是否存在交叉
>>> P.closed(1, 2).overlaps(P.closed(2, 3))
True
>>> P.closed(1, 2).overlaps(P.open(2, 3))
False

Interval间比较

import portion as P

# 判断区间相等
>>> P.closed(0, 2) == P.closed(0, 1) | P.closed(1, 2)
True

# 判断区间大小(根据其在坐标轴上的左右分布来判断,不允许有交叉)
## a < b、a > b运算,完全不允许有交叉
>>> P.closed(0, 1) < P.closed(2, 3)
True
>>> P.closed(0, 1) < P.closed(1, 2)
False
# a <= b、a >= b运算,允许有交叉,只需a位于b上界左侧、a位于b下界右侧即可
>>> P.closed(0, 2) <= P.closed(1, 3)
True
>>> P.closed(0, 3) <= P.closed(1, 2)
False

# 判断值与区间的关系
## 与之同理,x < i 需要x位于i下界左侧,x <= i 只需x位于i上界左侧即可
>>> 5 < P.closed(0, 10)
False
>>> 5 <= P.closed(0, 10)
True

# 注意上述比较操作与传统意义上的比较并不一致,因而存在某些Interval无法比较的情况
>>> P.closed(0, 4) <= P.closed(1, 2) or P.closed(0, 4) >= P.closed(1, 2)
False
>>> P.closed(0, 4) < P.closed(1, 2) or P.closed(0, 4) > P.closed(1, 2)
False
>>> P.empty() < P.empty()
True
>>> P.empty() < P.closed(0, 1) and P.empty() > P.closed(0, 1)
True

Interval修改

import portion as P

# replace方法进行修改

## 普通修改
>>> i = P.closed(0, 2)
>>> i.replace(P.OPEN, -1, 3, P.CLOSED)
(-1,3]
>>> i.replace(lower=1, right=P.OPEN)
[1,2)

## 进阶修改(传递函数)
>>> P.closed(0, 2).replace(upper=lambda x: 2 * x)
[0,4]

### 对于infinity的特殊情况
>>> i = P.closedopen(0, P.inf)
>>> i.replace(upper=lambda x: 10)  # No change, infinity is ignored
[0,+inf)
>>> i.replace(upper=lambda x: 10, ignore_inf=False)  # Infinity is not ignored
[0,10)

### 对于非atomic的Interval,其会进行扩展或者加以限制
>>> i = P.openclosed(0, 1) | P.closed(5, 10)
>>> i.replace(P.CLOSED, -1, 8, P.OPEN)
[-1,1] | [5,8)
>>> i.replace(lower=4)
(4,10]

### 对于自定义函数进行修改,其支持apply方法
>>> i = P.closed(2, 3) | P.open(4, 5)
>>> i.apply(lambda x: (x.left, x.lower + 1, x.upper + 1, x.right)) # 增加上下界数值
[3,4] | (5,6)
>>> i.apply(lambda x: (~x.left, x.lower, x.upper, ~x.right)) # 修改开闭区间情况
(2,3) | [4,5]

### apply方法还可与replace方法结合,增加其灵活性
>>> i = P.openclosed(-P.inf, 0) | P.closed(3, 4) | P.closedopen(8, P.inf)
>>> i.apply(lambda x: x.replace(upper=lambda v: v + 1)) # 增加上下界数值
(-inf,1] | [3,5] | [8,+inf)
>>> i.apply(lambda x: x.replace(lower=lambda v: v * 2)) # Interval仍会被自动简化
(-inf,0] | [16,+inf)
>>> i.apply(lambda x: x.replace(left=lambda v: ~v, right=lambda v: ~v)) # 修改开闭区间情况
(-inf,0) | (3,4) | (8,+inf)
>>> conv = lambda v: -10 if v == -P.inf else (10 if v == P.inf else v)
>>> i.apply(lambda x: x.replace(lower=conv, upper=conv, ignore_inf=False)) # 修改上下界的infinity为其他数值
(-10,0] | [3,4] | [8,10)

遍历Interval

import portion as P

# iterate方法
>>> list(P.iterate(P.closed(0, 3), step=1)) # 以指定步长step来遍历Interval
[0, 1, 2, 3]
>>> list(P.iterate(P.closed(0, 3), step=2))
[0, 2]
>>> list(P.iterate(P.open(0, 3), step=2))
[2]

## 对于非atomic的Interval对象,其会连续访问所有子atomic区间并返回值
>>> list(P.iterate(P.singleton(0) | P.singleton(3) | P.singleton(5), step=2))  # Won't be [0]
[0, 3, 5]
>>> list(P.iterate(P.closed(0, 2) | P.closed(4, 6), step=3))  # Won't be [0, 6]
[0, 4]

## 对于非整型或存在infinity上下界的Interval,可设置base参数来调整结果(接受可执行函数,并以下界对应的值作为基底)
>>> list(P.iterate(P.closed(0.3, 4.9), step=1, base=int)) # 调整base为int类型
[1, 2, 3, 4]
>>> list(P.iterate(P.openclosed(-P.inf, 2), step=1, base=lambda x: max(0, x))) # 将base设置为从0开始
[0, 1, 2]

## base参数调整同样支持非atomic的Interval
>>> base = lambda x: 0
>>> list(P.iterate(P.singleton(0) | P.singleton(3) | P.singleton(5), step=2, base=base))
[0]
>>> list(P.iterate(P.closed(0, 2) | P.closed(4, 6), step=3, base=base))
[0, 6]

## 反向遍历Interval,设置参数reverse=True
>>> list(P.iterate(P.closed(0, 3), step=-1, reverse=True))  # Mind step=-1
[3, 2, 1, 0]
>>> list(P.iterate(P.closed(0, 3), step=-2, reverse=True))  # Mind step=-2
[3, 1]

## 对于非数值区间的Interval,可通过设置step参数来调整遍历步长(接受可执行函数,input为当前值,output为下一个输出值)
>>> list(P.iterate(P.closed('a', 'd'), step=lambda d: chr(ord(d) + 1)))
['a', 'b', 'c', 'd']
>>> list(P.iterate(P.closed('a', 'd'), step=lambda d: chr(ord(d) - 1), reverse=True))
['d', 'c', 'b', 'a']

匹配Interval与变量(IntervalDict结构)

import portion as P

# 新建IntervalDict对象(key为Interval对象,value为变量)
>>> d = P.IntervalDict()
>>> d[P.closed(0, 3)] = 'banana'
>>> d[4] = 'apple'
>>> d
{[0,3]: 'banana', [4]: 'apple'}

# 添加新key-value对会动态更新当前IntervalDict对象
>>> d[P.closed(2, 4)] = 'orange'
>>> d
{[0,2): 'banana', [2,4]: 'orange'}

# 单值访问IntervalDict
>>> d[2]
'orange'

# Interval访问IntervalDict
>>> d[~P.empty()]  # 获取所有键值对,等同于d.copy()
{[0,2): 'banana', [2,4]: 'orange'}
>>> d[P.closed(1, 3)]
{[1,2): 'banana', [2,3]: 'orange'}
>>> d[P.closed(-2, 1)]
{[0,1]: 'banana'}
>>> d[P.closed(-2, -1)]
{}

# get方法访问IntervalDict(可设置default参数作为默认值),参数为key,返回value
>>> d.get(5, default=0)
0
>>> d.get(P.closed(-2, 1), default='peach')
{[-2,0): 'peach', [0,1]: 'banana'}
>>> d.get(P.closed(-2, -1), default='peach')
{[-2,-1]: 'peach'}

# find方法访问IntervalDict,参数为value,返回key
>>> d.find('banana')
[0,2)
>>> d.find('orange')
[2,4]
>>> d.find('carrot')
()

# 检查IntervalDict中所有key的范围、key、value和key-value对
>>> d.domain()
[0,4]
>>> list(d.keys())
[[0,2), [2,4]]
>>> list(d.values())
['banana', 'orange']
>>> list(d.items())
[([0,2), 'banana'), ([2,4], 'orange')]

## 若两个不同Interval具有相同value,则会被合并为非连续Interval返回
>>> d = P.IntervalDict()
>>> d[P.closed(0, 1)] = d[P.closed(2, 3)] = 'peach'
>>> list(d.items())
[([0,1] | [2,3], 'peach')]

# combine方法合并2个IntervalDict对象,返回新的IntervalDict,可设置how参数来调整交集区间的value合并方式
>>> d1 = P.IntervalDict({P.closed(0, 2): 'banana'})
>>> d2 = P.IntervalDict({P.closed(1, 3): 'orange'})
>>> concat = lambda x, y: x + '/' + y
>>> d1.combine(d2, how=concat)
{[0,1): 'banana', [1,2]: 'banana/orange', (2,3]: 'orange'}

## 其他合并方式(向左合并、向右合并、合并为交集)
>>> d = d1.combine(d2, how=concat)
>>> d[d1.domain()]  # 向左合并
{[0,1): 'banana', [1,2]: 'banana/orange'}
>>> d[d2.domain()]  # 向右合并
{[1,2]: 'banana/orange', (2,3]: 'orange'}
>>> d[d1.domain() & d2.domain()]  # 合并为交集
{[1,2]: 'banana/orange'}

# P.S: IntervalDict支持dict对象的其他内置方法
# An IntervalDict also supports len, in and del, and defines .clear, .copy, .update, .pop, .popitem, and .setdefault.
# For convenience, one can export the content of an IntervalDict to a classical Python dict using the as_dict method.

导出/导入Interval对象至字符串

import portion as P

# to_string方法导出Interval为字符串
>>> P.to_string(P.closedopen(0, 1))
'[0,1)'

## 格式化导出为字符串
>>> params = {
...   'disj': ' or ',
...   'sep': ' - ',
...   'left_closed': '<',
...   'right_closed': '>',
...   'left_open': '..',
...   'right_open': '..',
...   'pinf': '+oo',
...   'ninf': '-oo',
...   'conv': lambda v: '"{}"'.format(v),
... }
>>> x = P.openclosed(0, 1) | P.closed(2, P.inf)
>>> P.to_string(x, **params)
'.."0" - "1"> or <"2" - +oo..'

# from_string方法导入字符串为Interval,可设置conv参数为对应转换函数
>>> P.from_string('[0, 1]', conv=int) == P.closed(0, 1)
True
>>> P.from_string('[1.2]', conv=float) == P.singleton(1.2)
True
>>> converter = lambda s: datetime.datetime.strptime(s, '%Y/%m/%d')
>>> P.from_string('[2011/03/15, 2013/10/10]', conv=converter)
[datetime.datetime(2011, 3, 15, 0, 0),datetime.datetime(2013, 10, 10, 0, 0)]

## 格式化导入
>>> s = '.."0" - "1"> or <"2" - +oo..'
>>> params = {
...   'disj': ' or ',
...   'sep': ' - ',
...   'left_closed': '<',
...   'right_closed': '>',
...   'left_open': r'\.\.',  # from_string expects regular expression patterns
...   'right_open': r'\.\.',  # from_string expects regular expression patterns
...   'pinf': r'\+oo',  # from_string expects regular expression patterns
...   'ninf': '-oo',
...   'conv': lambda v: int(v[1:-1]),
... }
>>> P.from_string(s, **params)
(0,1] | [2,+inf)

## 高阶格式化导入,可调整bound参数为相应正则表达式来导入复杂字符串
>>> s = '[(0, 1), (2, 3)]'  # Bounds are expected to be tuples
>>> P.from_string(s, conv=eval, bound=r'\(.+?\)')
[(0, 1),(2, 3)]

导出/导入Interval对象至Python内置数据类型

import portion as P

# to_data方法导出Interval至大小为4的元组tuple(P.CLOSED以True、P.OPEN以False代替),便于JSON序列化输出
>>> P.to_data(P.openclosed(0, 2))
[(False, 0, 2, True)]
>>> x = P.openclosed(0, 1) | P.closedopen(2, P.inf) # Infinity以float('inf')或float('-inf')来表示
>>> P.to_data(x)
[(False, 0, 1, True), (True, 2, inf, False)]

## 格式化导出,可调整conv参数为相应函数来格式化导出字符串
>>> x = P.closedopen(datetime.date(2011, 3, 15), datetime.date(2013, 10, 10))
>>> P.to_data(x, conv=lambda v: (v.year, v.month, v.day))
[(True, (2011, 3, 15), (2013, 10, 10), False)]

# from_data方法导入大小为4的元组tuple至Interval,conv参数用以确定相应转换函数
>>> x = [(True, (2011, 3, 15), (2013, 10, 10), False)]
>>> P.from_data(x, conv=lambda v: datetime.date(*v))
[datetime.date(2011, 3, 15),datetime.date(2013, 10, 10))
  • 9
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值