最小化并重新排列lis

2024-03-29 15:45:36 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个列表,我想减少列表中的值的数量。所以我对列表进行排序并尝试使用范围,但我有点卡住了。你知道吗

迄今为止的代码:

ports=["1/1/1","1/1/3","2/1/5", "1/1/2", "2/1/6" ]
arange=[]
brange=[]
def test():
   for i in ports:
       num=i.split("/")
       portnum=num [-1]
       arange.append(portnum)
   portindex=i[:-1]
   arange.sort()
   for i in range(len(arange)-1):
       a, b= int (arange[i]), int (arange[i+1]) 
       if (a+1) == b:
           brange.append(portindex+arange[i]+"-"+str(b))
   print (brange)
test()

我得到的结果是:

['2/1/1-2', '2/1/2-3', '2/1/5-6']

我真正想要的是

['1/1/1-3','2/1/5-6']

有什么线索吗?你知道吗


Tags: 代码intest列表for数量排序ports
3条回答

下面是一个使用^{}的解决方案。它首先将端口分组到defaultdict列表中,然后使用minmax()实用程序函数输出分组的结果范围。你知道吗

from collections import defaultdict

ports = ["1/1/1", "1/1/3", "2/1/5", "1/1/2", "2/1/6"]

def minmax(numbers):
    """Returns minumum and maximum numbers in sequence"""
    return min(numbers), max(numbers)

# Group ports
d = defaultdict(list)
for port in ports:
    key, number = port.rsplit("/", 1)
    d[key].append(number)

print(["%s/%d-%d" % (k, *minmax(list(map(int, v)))) for k, v in d.items()])
# ['1/1/1-3', '2/1/5-6']

注意:str.rsplit()从右侧拆分。特别是在这种情况下,从右边开始的第一个1delimeter。你知道吗

更新

如果要处理丢失的端口,可以尝试此函数:

from collections import defaultdict
from operator import itemgetter
from itertools import groupby

def group_ports(ports):
    result = []

    # Group ports
    port_groups = defaultdict(list)
    for port in ports:
        key, number = port.rsplit("/", 1)
        port_groups[key].append(number)

    # Go through each port group
    for port, ranges in port_groups.items():

        # Sort ranges
        sorted_range = sorted(map(int, ranges))

        # Iterate grouped consecutive numbers 
        # e.g. [1,2,3,4,6,7] -> [[1,2,3,4], [6,7]]
        for _, g in groupby(enumerate(sorted_range), key=lambda x: x[0] - x[1]):
            # Get only numbers in sequence
            sequence = list(map(itemgetter(1), g))

            # Append port strings
            # Singleton sequences will be port/number, otherwise port/min-max
            result.append(
                "%s/%d" % (port, sequence[0])
                if len(sequence) == 1
                else "%s/%d-%d" % (port, sequence[0], sequence[-1])
            )

    return result

print(group_ports(["1/1/1", "1/1/3", "2/1/5", "1/1/2", "2/1/6"]))
print(group_ports(["1/1/1", "1/1/3", "1/1/2", "1/2/1", "1/2/3", "1/2/4"]))

输出:

['1/1/1-3', '2/1/5-6']
['1/1/1-3', '1/2/1', '1/2/3-4']

虽然还有其他更整洁的解决方案,但我的有点不同。 其他的只取最小值和最大值,这意味着如果您输入:

minify(['1/1/1','1/1/900'])

您将获得:

['1/1/1-900']

这可能不是你想要的。你知道吗

当两个端口之间的距离超过1时,我的函数将创建一个新组:

['1/1/1', '1/1/900']

def minify(ports):
    ports.sort()
    heads = []
    tails = []
    for port in ports:
        s = port.split('/')
        heads.append('/'.join(s[:-1]))
        tails.append(s[-1])

    combined = zip(heads, tails)
    d = {}

    for i, port in enumerate(combined):
        if port[0] not in d:
            d[port[0]] = [int(port[1])]
        else:
            d[port[0]].append(int(port[1]))

    for _, typus in d.items():
        typus.sort()

    print(d)

    d_groups = {}

    for head, tails in d.items():
        d_groups[head] = []
        for tail in tails:
            tail = int(tail)
            in_group = False
            for group in d_groups[head]:
                print(tail, group)
                if tail >= group[0] and tail <= group[1]:
                    in_group = True
                    break
                elif tail > group[1] and tail == group[1] + 1:
                    in_group = True
                    group[1] += 1
                    break

            if not in_group:
                d_groups[head].append([int(tail), (tail)])

    tidy_groups = []
    for key, value in d_groups.items():
        for group in value:
            if group[0] == group[1]:
                tidy_groups.append(f'{key}/{group[0]}')
            else:
                tidy_groups.append(f'{key}/{group[0]}-{group[1]}')

    return tidy_groups

我想这会满足你的要求:

ports=["1/1/1","1/1/3","2/1/5", "1/1/2", "2/1/6" ]

def minimize_list(ports):
    ports = [x.split("/") for x in ports]

    temp_new_ports = {}

    for n in ports:
        if not n[0] in temp_new_ports.keys():
            temp_new_ports[n[0]] = {}
        if not n[1] in temp_new_ports[n[0]].keys():
            temp_new_ports[n[0]][n[1]] = []

        temp_new_ports[n[0]][n[1]].append(n[2])
        temp_new_ports[n[0]][n[1]].sort()

    new_ports = []
    for key,value in temp_new_ports.items():
        for key2, value2 in value.items():
            this_entry = f"{key}/{key2}/"

            _min, _max = value2[0], value2[-1]
            if _min == _max:
                this_entry += str(_min)
            elif int(_max) - int(_min) + 1 == len(value2):
                this_entry += f"{_min}-{_max}"
            else:
                this_entry += ','.join(value2)
            new_ports.append(this_entry)

    return new_ports

print(minimize_list(ports))

输出:

['1/1/1-3', '2/1/5-6']

相关问题 更多 >