查找语义版本是否是另一个版本的超集 python
find if a semantic version is superset of of another version python
我有一个用例,其中我有一个 Java maven 语义范围列表,试图找到我可以在我的应用程序中排除的版本列表。
示例:
SemVersion1 = "[,1.8.8.1)"
SemVersion2 = "[,1.8.8.2)"
SemVersion3 = "[,1.8.8.3)"
SemVersion4 = "[1.0.0, 1.4.4)"
SemVersion5 = "[,1.3.11),[,1.7.0), [,1.8.0)"
如何过滤各种 SemVersion
以仅保留包含所有其他版本的版本。在这种情况下,将选取 SemVersion3
,因为它包含所有版本。
在python中考虑这样的事情:
output = []
for a in SemVersions:
is_redundent = False
for b in a:
if affected_versions[a].issuperset(affected_versions[b]):
is_redundent = True
break
if not is_redundent:
output.append(b)
问题是我需要给 SemVersions
充气才能得到 affected_versions
,有没有更简单的方法。
步骤:
- 将您的范围转换为更严格的表示法以消除
',1.2.3.4'
和“1.0,2.3.4”(我们需要最后一步的精确下限)
- 将您的字符串转换为实际的 Version 对象以便于比较(您也可以转换为数字元组,但它们会在包含非数字字符的版本上中断)
from packaging.version import Version
from functools import cmp_to_key
from collections import defaultdict
def adj_lengths(s, c=3):
"""Add missing .0 to a version up to a predefined count '.'-count.
Example: '9.0.2' with c == 3 -> '9.0.2.0'"""
cnt = s.count(".")
if c>cnt:
s = s + ".0"*(c-cnt)
return s
def split_mult(s):
"""Make versions more precise by replacing implicit range starts.
Uses adj_lengths to add missing .0 to equalize version lengths.
Handles splitting multiple given ranges as well.
Returns iterable.
Example: '[,1.3.11),[,1.7.0), [,1.8.0)'
-> (['0.0.0.0', '1.3.11.0'],['0.0.0.0', '1.7.0.0'], ['0.0.0.0', '1.8.0.0'])"""
s = s.replace("[,",f"[0,")
s1 = [ adj_lengths(b) for b in (t.strip("[()] ") for t in s.split(","))]
yield from [ s1[i:i+2] for i in range(0,len(s1),2)]
def make_version(l):
"""Transform text-list into Version-tuple."""
return ( Version(l[0]), Version(l[1]) )
计划:
vers = ["[,1.8.8.1)",
"[,1.8.8.2)",
"[,1.8.8.3)",
"[1.0.0, 1.4.4)",
"[,1.3.11),[,1.7.0), [,1.8.0)"]
# preprocessing to make them nicer
vers2 = []
for tmp in (split_mult(a) for a in vers) :
vers2.extend( (make_version(k) for k in tmp) )
print(vers2)
# bring into order
vers2.sort()
# use the lower bound as key - append alle upper bounds to a defaultdict(list)
d = defaultdict(list)
for fr,to in vers2:
d[fr].append(to)
# simplify lower bound:[list of upper bounds] to (lower bound, max(upper bound list values))
vers3 = [ (k,max(v)) for k,v in d.items()]
# eliminate range that lie inside the 1st elements range
for item in vers3[1:][:]:
if item[0] >= vers3[0][0] and item[1] <= vers3[0][1]:
vers3.remove(item)
print(vers3)
输出:
[(<Version('0.0.0.0')>, <Version('1.8.8.3')>)]
如果结果范围不止一个,则必须对每个元素执行最后一步 - 而不仅仅是第一个,f.e。当您在最后一步中的数据如下:
[(<Version('0.0.0.0')>, <Version('1.8.8.3')>),
(<Version('1.0.0.0')>, <Version('2.8.8.3')>),
(<Version('1.2.0.0')>, <Version('1.8.8.3')>), ] # last elem inside before-last elem
我有一个用例,其中我有一个 Java maven 语义范围列表,试图找到我可以在我的应用程序中排除的版本列表。
示例:
SemVersion1 = "[,1.8.8.1)"
SemVersion2 = "[,1.8.8.2)"
SemVersion3 = "[,1.8.8.3)"
SemVersion4 = "[1.0.0, 1.4.4)"
SemVersion5 = "[,1.3.11),[,1.7.0), [,1.8.0)"
如何过滤各种 SemVersion
以仅保留包含所有其他版本的版本。在这种情况下,将选取 SemVersion3
,因为它包含所有版本。
在python中考虑这样的事情:
output = []
for a in SemVersions:
is_redundent = False
for b in a:
if affected_versions[a].issuperset(affected_versions[b]):
is_redundent = True
break
if not is_redundent:
output.append(b)
问题是我需要给 SemVersions
充气才能得到 affected_versions
,有没有更简单的方法。
步骤:
- 将您的范围转换为更严格的表示法以消除
',1.2.3.4'
和“1.0,2.3.4”(我们需要最后一步的精确下限) - 将您的字符串转换为实际的 Version 对象以便于比较(您也可以转换为数字元组,但它们会在包含非数字字符的版本上中断)
from packaging.version import Version
from functools import cmp_to_key
from collections import defaultdict
def adj_lengths(s, c=3):
"""Add missing .0 to a version up to a predefined count '.'-count.
Example: '9.0.2' with c == 3 -> '9.0.2.0'"""
cnt = s.count(".")
if c>cnt:
s = s + ".0"*(c-cnt)
return s
def split_mult(s):
"""Make versions more precise by replacing implicit range starts.
Uses adj_lengths to add missing .0 to equalize version lengths.
Handles splitting multiple given ranges as well.
Returns iterable.
Example: '[,1.3.11),[,1.7.0), [,1.8.0)'
-> (['0.0.0.0', '1.3.11.0'],['0.0.0.0', '1.7.0.0'], ['0.0.0.0', '1.8.0.0'])"""
s = s.replace("[,",f"[0,")
s1 = [ adj_lengths(b) for b in (t.strip("[()] ") for t in s.split(","))]
yield from [ s1[i:i+2] for i in range(0,len(s1),2)]
def make_version(l):
"""Transform text-list into Version-tuple."""
return ( Version(l[0]), Version(l[1]) )
计划:
vers = ["[,1.8.8.1)",
"[,1.8.8.2)",
"[,1.8.8.3)",
"[1.0.0, 1.4.4)",
"[,1.3.11),[,1.7.0), [,1.8.0)"]
# preprocessing to make them nicer
vers2 = []
for tmp in (split_mult(a) for a in vers) :
vers2.extend( (make_version(k) for k in tmp) )
print(vers2)
# bring into order
vers2.sort()
# use the lower bound as key - append alle upper bounds to a defaultdict(list)
d = defaultdict(list)
for fr,to in vers2:
d[fr].append(to)
# simplify lower bound:[list of upper bounds] to (lower bound, max(upper bound list values))
vers3 = [ (k,max(v)) for k,v in d.items()]
# eliminate range that lie inside the 1st elements range
for item in vers3[1:][:]:
if item[0] >= vers3[0][0] and item[1] <= vers3[0][1]:
vers3.remove(item)
print(vers3)
输出:
[(<Version('0.0.0.0')>, <Version('1.8.8.3')>)]
如果结果范围不止一个,则必须对每个元素执行最后一步 - 而不仅仅是第一个,f.e。当您在最后一步中的数据如下:
[(<Version('0.0.0.0')>, <Version('1.8.8.3')>),
(<Version('1.0.0.0')>, <Version('2.8.8.3')>),
(<Version('1.2.0.0')>, <Version('1.8.8.3')>), ] # last elem inside before-last elem