如何压缩字符串的python列表,格式为字符串[number] / [number]

时间:2014-05-30 08:38:16

标签: python

我有一个以数字结尾的字符串列表。想要在python中对它们进行排序,然后在形成范围时压缩它们。

例如输入字符串:

ABC1/3, ABC1/1, ABC1/2, ABC2/3, ABC2/2, ABC2/1

例如输出字符串:

ABC1/1-3, ABC2/1-3

我应该如何使用python解决这个问题?

3 个答案:

答案 0 :(得分:3)

没有必要使用dict来解决这个问题。您可以简单地将令牌解析为列表并对其进行排序。默认情况下,Python按每个列表的各个元素对列表列表进行排序。排序令牌对列表后,您只需迭代一次并记录重要索引。试试这个:

# Data is a comma separated list of name/number pairs.

data = 'ABC1/3, ABC1/1, ABC1/2, ABC2/3, ABC2/2, ABC2/1'

# Split data on ', ' and split each token on '/'.

tokens = [token.split('/') for token in data.split(', ')]

# Convert token number to integer.

for index in range(len(tokens)):
    tokens[index][1] = int(tokens[index][1])

# Sort pairs, automatically orders lists by items.

tokens.sort()

prev = 0     # Record index of previous pair's name.
indices = [] # List to record indices for output.

for index in range(1, len(tokens)):

    # If name matches with previous position.

    if tokens[index][0] == tokens[prev][0]:

        # Check whether number is increasing sequentially.

        if tokens[index][1] != (tokens[index - 1][1] + 1):

            # If non-sequential increase then record the indices.

            indices.append((prev, index - 1))
            prev = index

    else:

        # If name changes then record the indices.

        indices.append((prev, index - 1))
        prev = index

# After iterating the list, record the indices.

indices.append((prev, index))

# Print the ranges.

for start, end in indices:
    if start == end:
        args = (tokens[start][0], tokens[start][1])
        print '{0}/{1},'.format(*args),
    else:
        args = (tokens[start][0], tokens[start][1], tokens[end][1])
        print '{0}/{1}-{2},'.format(*args),

# Output:
# ABC1/1-3 ABC2/1-3

答案 1 :(得分:2)

我想快速解决这个问题,所以这里有一个几乎完整的解决方案,基于我自己的make_range_stringstolen natsort

import re
from collections import defaultdict

def sortkey_natural(s):
    return tuple(int(part) if re.match(r'[0-9]+$', part) else part
                for part in re.split(r'([0-9]+)', s))

def natsort(collection):
    return sorted(collection, key=sortkey_natural)

def make_range_string(collection):
    collection = sorted(collection)
    parts = []

    range_start = None
    previous = None

    def push_range(range_start, previous):
        if range_start is not None:
            if previous == range_start:
                parts.append(str(previous))
            else:
                parts.append("{}-{}".format(range_start, previous))

    for i in collection:
        if previous != i - 1:
            push_range(range_start, previous)
            range_start = i

        previous = i

    push_range(range_start, previous)
    return ', '.join(parts)

def make_ranges(strings):
    components = defaultdict(list)
    for i in strings:
        main, _, number = i.partition('/')
        components[main].append(int(number))

    rvlist = []
    for key in natsort(components):
        rvlist.append((key, make_range_string(components[key])))

    return rvlist

print(make_ranges(['ABC1/3', 'ABC1/1', 'ABC1/2', 'ABC2/5', 'ABC2/2', 'ABC2/1']))

代码打印元组列表:

[('ABC1', '1-3'), ('ABC2', '1-2, 5')]

答案 2 :(得分:1)

我首先要分割字符串,然后使用你要匹配的部分作为字典键。

strings = ['ABC1/3', 'ABC1/1', 'ABC1/2', 'ABC2/3', 'ABC2/2', 'ABC2/1']
d = {}
for s in string:
    a, b = s.split('/')
    d.get(a, default=[]).append(b)

将数字部分收集到每个前缀的列表中。然后,您可以对列表进行排序,并查找要加入的相邻数字。