在python中解析元组列表并消除双精度
我有以下问题: 我有一个表示软件包及其版本的元组列表。一些软件包没有指定的版本,因此没有问题,如:在python中解析元组列表并消除双精度,python,list,python-3.x,Python,List,Python 3.x,我有以下问题: 我有一个表示软件包及其版本的元组列表。一些软件包没有指定的版本,因此没有问题,如: ('lib32c-dev', '', '', '') ('libc6-i386', '2.4', '', '') ('lib32c-dev', '', '', '') ('libc6-i386', '1.06', '', '') ('libc6-i386', '2.4', '', '') ('lib32c-dev', '', '', '')
('lib32c-dev', '', '', '')
('libc6-i386', '2.4', '', '')
('lib32c-dev', '', '', '')
('libc6-i386', '1.06', '', '')
('libc6-i386', '2.4', '', '')
('lib32c-dev', '', '', '')
('libc6-i386', '2.16', '', '')
('libc6-dev', '', '', '')
('', '', 'libc-dev', '')
('libc6-dev', '', '', '')
('', '', 'libc-dev', '')
('libncurses5-dev', '5.9+20150516-2ubuntu1', '', '')
('libc6-dev-x32', '', '', '')
('libc6-x32', '2.16', '', '')
('libncursesw5-dev', '5.9+20150516-2ubuntu1', '', '')
('libc6-dev-x32', '', '', '')
('libc6-x32', '2.16', '', '')
('libc6-dev-x32', '', '', '')
('libc6-x32', '2.16', '', '')
('libncurses5-dev', '5.9+20150516-2ubuntu1', '', '')
('libncursesw5-dev', '5.9+20150516-2ubuntu1', '', '')
如您所见,有些包多次以元组列出,但版本不同
我需要的是解析元组列表,以便在将列表转换为字典之前为每个包提供最新版本
PS:包名的位置及其版本不是固定的。但是我们可以说版本总是在包名之后,所以我们可以说版本总是在位置1和3吗
谢谢你的帮助。你应该先把它转换成字典
data = {}
for value in my_list:
data2 = iter(value)
#find the first non-empty entry in our subtuple, that is our package name
name = next(d for d in data2 if d)
version = next(data2,'') # the version is whatever immediatly follows the package name
data.setdefault(name,[]).append(version)
这将使您实现90%的目标,尽管这取决于包名是第一个元素。。。这显然并不总是正确的
下面是一种从字符串中获取版本号的方法
def float_version_from_string(version_string):
try:
return float(re.findall("\d.?\d*",version_string)[0])
except (IndexError,ValueError):
return -1
这只是一个动态编写的虚拟实现。它没有经过测试,只有当元组的第一个元素是包名,第二个元素是它的版本时,它才应该工作。这可能不会给你确切的解决方案,但它肯定会帮助你解决问题
my_list_of_tuples = [...] # some list
my_new_list = []
for tuple in my_list_of_tuples:
version = float(tuple[1])
package_name = tuple[0]
for tuple in my_new_list:
if tuple[0] == package_name and float(tuple[1]) > version:
my_new_list.append(tuple)
当且仅当更新版本不存在时,您可以迭代列表,并将包放入dict中:
def version_as_list(s):
"""Converts string symoblizing version to list of integers
for comparsion purposes."""
return [int(i) for i in s.split('.')]
data = {}
for name, version, _, _:
if vesion_as_list(data.get(name, '')) < version_as_list(version):
data[name] = version
使用大量Python内置/库代码。这似乎是一个很长的解决方案,但实际上并非如此——这是因为我将文档放在了两者之间。代码只有7行
import re, itertools
pkgs = [('libc', '', '', ''), ... ] # your list of tuples
# a function to extract a version number from a string
rxVSN = re.compile('^(?P<vsn>\d+(\.\d+)?)')
def version(s):
mo = rxVSN.match(s)
return float(mo.group('vsn')) if mo is not None else 0.0
# step one: sort the list of tuples by package name and reverse version
# uses built-in sorted() function
# https://docs.python.org/2/library/functions.html#sorted
pkgs = sorted( pkgs, key = lambda tup: (tup[0], -version(tup[1])) )
# Now we can use the itertools.groupby() function to group the
# tuples by package name. Then we take the first element of each
# group because that is the one with the highest version number
# (because that's how we sorted them ...)
# https://docs.python.org/2/library/itertools.html#itertools.groupby
for (pkg, versions) in itertools.groupby( pkgs, key=lambda tup: tup[0]):
print pkg,": ", next(versions)
我找到了理想的解决办法。我用过:
apt_pkg.version_compare(a,b).
谢谢大家
功能:
def comparePackages(package_dictionary):
#loop in keys and values of package_dictionary
for package_name, list_versions in zip(package_dictionary.keys(), package_dictionary.values()) :
#loop on each sublist
for position in xrange(len(list_versions)) :
a = str(list_versions[position])
b = str(list_versions[position-1])
#the only way it worked was by using a and b
vc = apt_pkg.version_compare(a,b)
if vc > 0:
#a>b
max_version = a
elif vc == 0:
#a==b
max_version = a
elif vc < 0:
#a<b
max_version = b
del list_versions[:]
if(max_version is '') :
max_version = 'Not Specified'
package_dictionary[package_name] = max_version
棘手的部分是找到一个比较函数来可靠地确定哪个版本更新。例如,我们想把2.16作为新的2.4,但是一个幼稚的字符串比较是不够的。更重要的是,浮点比较不仅不够,而且在无法将版本转换为浮点时还会引发ValueError 所需的排序类型可以称为自然排序或人工排序,在中有一些解决方案 可用于精确比较两个值而不是对列表排序的实现可能类似于:
import re
def tryint(s):
try:
return int(s)
except:
return s
def getchunks(s):
return [tryint(c) for c in re.split('([0-9]+)', s)]
def compare_strings(s1, s2):
return getchunks(s1) > getchunks(s2)
# 2.4 < 2.16
# 2.4 < 2.4.1
# a_1 < a_2
# and so on...
最终结果是:
'lib32c-dev': ''
'libc6-x32': '2.16'
'libc6-i386': '2.16'
'libncurses5-dev': '5.9+20150516-2ubuntu1'
'libc6-dev': ''
'libc-dev': ''
'libncursesw5-dev': '5.9+20150516-2ubuntu1'
'libc6-dev-x32': ''
请注意,比较_字符串不符合十进制顺序,例如2.001==2.1;实现这个细节会使代码更加混乱,而且可能与此无关。此外,如果不希望进行区分大小写的比较,可以更新tryint函数,在最后一行中使用s.lower
编辑:您的解决方案应该可以工作,但我通常建议在迭代字典时不要修改它。此外,压缩键和值似乎是可靠的,但调用项更容易。最后,行del list_versions[:]是荒谬的;它创建一个全新的列表只是为了删除它。您可以用更简洁的方式重写函数,如下所示:
from functools import cmp_to_key
def compare_packages(package_dictionary):
new_dictionary = {}
for package, versions in package_dictionary.items():
version = max(versions, key=cmp_to_key(apt_pkg.version_compare))
new_dictionary[package] = version or 'Not Specified'
return new_dictionary
您可以在列表上迭代,并将包放入dict中,当且仅当其较新版本尚未存在时。谢谢您的评论。但问题是,我无法创建一个代码,如果版本更新或不更新,就可以获取…你能给我们看一段你已经尝试过的代码吗?我能想到的唯一方法是将元组视为一个列表并直观地解析它,但我不能这样做,因为包名的位置和它的版本(如果可用)是不固定的,我已经完成了但dict的问题如下:如果插入一个已经存在的键,它将修改旧值并放入新值。此外,软件包的位置和它的版本也不稳定,正如你在我的例子中看到的那样。。。因为这和你描述的不一样。。。但是它会崩溃,因为你不知道名字或版本会在哪里tuple@Marc添加了一些逻辑来尝试查找/猜测名称,它假定名称将是元组中的第一个非空值,并且版本立即跟随它是的,我在代码中使用了一个字典,如下所示:dictionnaire_package=dictTuple[I:I+2]对于xrange0中的i,lenTuple,2,但正如我之前在注释中所说的,如果该键已经存在于字典中,那么它的值将被自动替换。通过执行我的代码,我从每个元组中得到2个键和2个值,然后我进行了清理,这很好,但是有一个被替换的版本却无法控制替换,这真的是一个大问题,这是什么?这不是我答案的一部分。。。是的,你试过字典的答案。。。但这根本不是我的解决方案所做的。。。事实上,我不知道你粘贴的代码正在做什么,或者你希望它做什么。。。而且它与我的代码完全不同!您能解释一下为什么对“.”进行拆分吗?对不起,代码中有错误,请参阅编辑。字符串是一个字符接一个字符进行比较的,因此“10.0”<“2.7”,但[2,7]<[10,0],是一个
nd[]
from collections import defaultdict
lib_ver_dict = defaultdict(str)
for lib_tuple in lib_tuples:
generator = (string for string in lib_tuple if string)
lib, ver = next(generator), next(generator, '')
if compare_strings(ver, lib_ver_dict[lib]):
lib_ver_dict[lib] = ver
'lib32c-dev': ''
'libc6-x32': '2.16'
'libc6-i386': '2.16'
'libncurses5-dev': '5.9+20150516-2ubuntu1'
'libc6-dev': ''
'libc-dev': ''
'libncursesw5-dev': '5.9+20150516-2ubuntu1'
'libc6-dev-x32': ''
from functools import cmp_to_key
def compare_packages(package_dictionary):
new_dictionary = {}
for package, versions in package_dictionary.items():
version = max(versions, key=cmp_to_key(apt_pkg.version_compare))
new_dictionary[package] = version or 'Not Specified'
return new_dictionary