组织唯一整数列表并尽可能创建范围/摘要

时间:2016-09-06 19:49:17

标签: python integer set

我正在尝试设置一个函数或类来存储具有添加,删除或检查存在的能力的唯一整数。这当然可以使用普通套装轻松实现。这里棘手的部分是显示范围。我的意思是,如果我有100到20000之间的所有数字,我不想显示中间所有数字的巨大列表,而是显示100-20000。

考虑以下示例:

numbers 3000,3008-3015,3020,3022,3030-3043,3068

目标是创建一个函数或类来添加,检查或检索有关当前数字的信息。以下是我的想象:

>>> f_check(3016) 
False
>>> f_check(3039)
True
>>> f_add(3016)
3000,3008-3016,3020,3022,3030-3043,3068
>>> f_remove(3039)
3000,3008-3016,3020,3022,3030-3038,3040-3043,3068    
>>> f_add(3100)
3000,3008-3016,3020,3022,3030-3038,3040-3043,3068,3100

依此类推......

同样,请注意范围部分(3030-3038,3040-3043)等。我不想显示连续数字的每个条目,而是显示“摘要”或范围。

再次使用相同的例子,如果我添加3021,我会期望以下结果:

>>> f_add(3021)
3000,3008-3016,3020-3022,3030-3043,3068

非常感谢您的想法!

3 个答案:

答案 0 :(得分:1)

正如评论中的人所说,你的大部分操作都是简单的列表操作。但是,如果您的数据包含范围(例如3008-3015),那么它就变成了另一个故事。原因是你需要对该范围的含义进行某种解码。 我只使用函数(没有类)编写了一个简单的代码。

matched = False

检查数字或范围:

def valueCheck(val):
    if "-" in val:
        return False
    else:
        return True

将范围编码为两个值(开始,结束)

def rangeCheck(val):
    if valueCheck(val):
        return val, val
    else:
        return val.split("-")

检查数字是否与列表内容匹配:

def f_check(new_number, numbers_list):
    global matched
    for i in numbers_list:
        rangeCheck(i)
        if int(rangeCheck(i)[0]) <= int(new_number) <= int(rangeCheck(i)[1]):
            print "{} matches {}".format(new_number, i)
            matched = True
            break
    if not matched:
        print "{} doesn't exist in your list".format(new_number)

在列表中添加一个数字:

def f_add(new_number, numbers_list):
    numbers_list.append(new_number)
    print numbers_list

从列表中删除一个数字:

def f_delete(new_number, numbers_list):
    numbers_list.remove(new_number)
    print numbers_list

假设您的数字是列表中的字符串值,如下所示:

numbers = ["3000", "3008-3015", "3020", "3022", "3030-3043", "3068"]

不匹配:

f_check("2000", numbers)
2000 doesn't exist in your list

单场比赛:

f_check("3020", numbers)
3020 matches 3020

范围匹配:

f_check("3010", numbers)
3010 matches 3008-3015

其他简单操作: 添加:

f_add("2000", numbers)
['3000', '3008-3015', '3020', '3022', '3030-3043', '3068', '2000']

删除:

f_delete("3068", numbers)
['3000', '3008-3015', '3020', '3022', '3030-3043']

请注意,使用以下内容可以更轻松地完成单个匹配:

number = "3020"
if number in numbers:
    print "{} matched".format(number)
3020 matched

更新#1

克服你提出的问题&#34;如果需要,可以将数字添加到现有范围和/或创建新范围。我在How to group list of continuous values in ranges找到了类似的问题,可以解决部分问题。但是,在这种情况下,您的原始编码(val-val)不会有用。 要解决此问题,您可以执行以下操作:

第1步,请注释以下两行:

# rangeCheck(i)
# if int(rangeCheck(i)[0]) <= int(new_number) <= int(rangeCheck(i)[1]):
"""
you will not be using the rangeCheck() or valueCheck() anymore.
"""

第2步,添加此行而不是原始的IF语句:

if int(i[0]) <= int(new_number) <= int(i[1]):

第3步,添加此功能可以压缩您的数字列表

def flatList(numbers_list):
    for i in numbers_list:
        if len(str(i).split("-")) > 1:
            numbers_list.extend(range(int(i.split("-")[0]), int(i.split("-")[1]) + 1))
            numbers_list.remove(i)
    return numbers_list

第4步,添加此功能(取自1),将您的单位列表分组为值范围

from operator import itemgetter
from itertools import groupby
def numbers_group(flatt_list):
    flatt_list = [int(i) for i in flatt_list]
    ranges = []
    for k, g in groupby(enumerate(flatt_list), lambda (i, x): i - x):
        group = map(itemgetter(1), g)
        ranges.append((group[0], group[-1]))
    return ranges

<强>用法:

numbers = ["3000", "3008-3015", "3020", "3022", "3030-3043", "3068"]

print flatList(numbers)
['3000', '3020', '3022', '3068', 3008, 3009, 3010, 3011, 3012, 3013, 3014, 3015, 3030, 3031, 3032, 3033, 3034, 3035, 3036, 3037, 3038, 3039, 3040, 3041, 3042, 3043]

print numbers_group(sorted(flatList(numbers)))
[(3008, 3015), (3030, 3043), (3000, 3000), (3020, 3020), (3022, 3022), (3068, 3068)]

numbers = f_add("3021", numbers)
print numbers_group(sorted(flatList(numbers)))
[(3008, 3015), (3030, 3043), (3000, 3000), (3020, 3022), (3068, 3068)]

numbers = f_delete("3021", numbers)
print numbers_group(sorted(flatList(numbers)))
[(3008, 3015), (3030, 3043), (3000, 3000), (3020, 3020), (3022, 3022), (3068, 3068)]

答案 1 :(得分:0)

由于您未指定格式化的含义,我假设您的意思是根据数字的升序排序数字列表。此外,我修改了您的列表并删除了某些数字之间的破折号。

话虽如此,我相信你要求的是sorted()功能。直接来自文档:

  

Python列表有一个内置的list.sort()方法,可以就地修改列表。还有一个sorted()内置函数,它从可迭代构建一个新的排序列表。

我只是创建一个类,然后添加上面列出的方法。这堂课很简单。这是我要做的一个例子:

class IntList:
  def __init__(self, *args):
    self.lst = [int(i) for i in args]
    self.lst.sort()

  def add(self, arg):
    self.lst.append(arg)
    self.lst.sort()

  def remove(self, arg):
    self.lst.remove(arg)
    self.lst.sort()

  def check(self, arg):
    return arg in self.lst

以下是一个示例用法:

>>> lst = IntList(1, 2, 3, 4, 5)
>>> lst.add(6)
>>> lst.lst
[1, 2, 3, 4, 5, 6]
>>> lst.remove(2)
>>> lst.lst
[1, 3, 4, 5, 6]
>>> lst.check(4)
True
>>> lst.check(90)
False

如果我的假设有误,请说明您的确切含义。

答案 2 :(得分:0)

好的,首先 - 感谢大家的努力。非常感谢。

这是我最终解决的问题。我只是用了一个类扩展了一个集合。修改它的输出。

class vlans(set):
  def check(self,number):
    if number in self:
        return True
  def __str__(self):
    last = 0
    out = []
    for x in list(self):
        if len(out)>0 and last+1==int(x):
            out[-1] = out[-1].split("-")[0]+"-"+str(x)
        else:
            out.append(str(x))
        last = int(x)
  return ",".join(out)

以下是它的工作原理:

>>> f=vlans([3008, 3009, 3010, 3011, 3012, 3013, 3014, 
    3015, 3020, 3022, 3030, 3031, 3032, 3033, 3034, 3035, 
    3036, 3037, 3038, 3039, 3040, 3041, 3042, 3000, 3068])
>>> 
>>> 
>>> print f
3000,3008-3015,3020,3022,3030-3042,3068
>>> f.check(3021)
>>> f.add(3021)
>>> f.check(3021)
True
>>> print f
3000,3008-3015,3020-3022,3030-3042,3068
>>> f.remove(3035)
>>> print f
3000,3008-3015,3020-3022,3030-3034,3036-3042,3068

对我所需要的模糊描述道歉,但希望现在一切都有意义!