Python 对非重复字符进行排序,然后对重复字符进行排序?

Python 对非重复字符进行排序,然后对重复字符进行排序?,python,string,algorithm,sorting,testing,Python,String,Algorithm,Sorting,Testing,我正在做以下编程练习:。声明如下: 任务 您将收到一个由小写字母和大写字母组成的字符串 字母和数字作为输入。您的任务是将此字符串作为 用短划线(“-”)分隔的块。块的元素应该是 根据下面列出的层次结构和每个块进行排序 不能包含同一字符的多个实例 层次结构是: lowercase letters (a - z), in alphabetic order uppercase letters (A - Z), in alphabetic order digits (0 - 9), in ascendi

我正在做以下编程练习:。声明如下:

任务

您将收到一个由小写字母和大写字母组成的字符串 字母和数字作为输入。您的任务是将此字符串作为 用短划线(“-”)分隔的块。块的元素应该是 根据下面列出的层次结构和每个块进行排序 不能包含同一字符的多个实例

层次结构是:

lowercase letters (a - z), in alphabetic order
uppercase letters (A - Z), in alphabetic order
digits (0 - 9), in ascending order
例子

"21AxBz" -> "xzAB12" - since input does not contain repeating characters, you only need 1 block
"abacad" -> "abcd-a-a" - character "a" repeats 3 times, thus 3 blocks are needed
"" -> "" - an empty input should result in an empty output
祝你好运

我编写了以下代码:

def blocks(s):
    print("s: "+s)
    lowers = []
    uppers = []
    digits = []
    for c in s:
        if c.islower():
            lowers.append(c)
        if c.isupper():
            uppers.append(c)
        if c.isdigit():
            digits.append(c)
    lowers.sort()
    uppers.sort()
    digits.sort()
    print("lowers: ")
    print(lowers)
    print("uppers: ")
    print(uppers)
    print("digits: ")
    print(digits)
    result = ""
    sorted = lowers+uppers+digits
    removedLetters = 0
    needsNextBlock = False
    nextBlock = "-"
    while len(sorted) > 0:
        for i, c in enumerate(sorted):
            print(i, c)
            print("result: ")
            print(result)
            if c not in result:
                result += c
                print("we want to delete: ")
                print(c)
                sorted = sorted[0:i-removedLetters] + sorted[i+1-removedLetters:]
                removedLetters += 1
                print("new sorted: ")
                print(sorted)
            else:
                if c not in nextBlock:
                    needsNextBlock = True
                    nextBlock += c
                    sorted = sorted[0:i-removedLetters] + sorted[i+1-removedLetters:]
                    removedLetters += 1

                    print("new sorted: ")
                    print(sorted)

        if needsNextBlock:
            result += nextBlock
        needsNextBlock = False
        nextBlock = "-"
    return result
还有一个bug,因为当我们进行以下测试时:

Test.assert_equals(blocks("abacad"), "abcd-a-a")
追踪是:

s: abacad
lowers: 
['a', 'a', 'a', 'b', 'c', 'd']
uppers: 
[]
digits: 
[]
0 a
result: 

we want to delete: 
a
new sorted: 
['a', 'a', 'b', 'c', 'd']
1 a
result: 
a
new sorted: 
['a', 'b', 'c', 'd']
2 a
result: 
a
3 b
result: 
a
we want to delete: 
b
new sorted: 
['a', 'c', 'd']
4 c
result: 
ab
we want to delete: 
c
new sorted: 
['a', 'd']
5 d
result: 
abc
we want to delete: 
d
new sorted: 
['a']
0 a
result: 
abcd-a
new sorted: 
['a']
0 a
result: 
abcd-a-a
new sorted: 
['a']
0 a
result: 
abcd-a-a-a
new sorted: 
['a']
0 a
result: 
abcd-a-a-a-a
new sorted: 
['a']
0 a
(infinite loop)
因此,正如我们看到的,当我们执行以下操作时,会产生困难:

sorted = sorted[0:i-removedLetters] + sorted[i+1-removedLetters:]
removedLetters += 1
因为我们之前已经传递了重复的字母,在本例中是“a”,但我们没有计算它,所以新排序的子字符串的演算保持不变

我尝试了一种天真的方法:

def blocks(s):
    print("\n\n\ns: "+s)
    lowers = []
    uppers = []
    digits = []
    for c in s:
        if c.islower():
            lowers.append(c)
        if c.isupper():
            uppers.append(c)
        if c.isdigit():
            digits.append(c)
    lowers.sort()
    uppers.sort()
    digits.sort()
    print("lowers: ")
    print(lowers)
    print("uppers: ")
    print(uppers)
    print("digits: ")
    print(digits)
    result = ""
    sorted = lowers+uppers+digits
    removedLetters = 0
    needsNextBlock = False
    nextBlock = "-"
    while len(sorted) > 0:
        initialIterationLength = len(sorted)
        for i, c in enumerate(sorted):
            print(i, c)
            print("result: ")
            print(result)
            if c not in result:
                result += c
                print("we want to delete: ")
                print(c)
                sorted = sorted[0:i-removedLetters] + sorted[i+1-removedLetters:]
                removedLetters += 1
                print("new sorted: ")
                print(sorted)
            else:
                if c not in nextBlock:
                    needsNextBlock = True
                    nextBlock += c
                    sorted = sorted[0:i-removedLetters] + sorted[i+1-removedLetters:]
                    removedLetters += 1
                    if initialIterationLength == len(sorted):
                        sorted = []
                    print("new sorted: ")
                    print(sorted)

        if needsNextBlock:
            result += nextBlock
        needsNextBlock = False
        nextBlock = "-"
    return result
如您所见,当我们开始while循环时,我添加了一句话:
initialIterationLength=len(sorted)
,在循环内部,在if条件下:

if initialIterationLength == len(sorted):
    sorted = []
它确实适用于正在讨论的测试,但是对于较大的输入,它将不起作用

例如,当输入为:

ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T
我们的结果是:

aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx
预计:

aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x
我认为应该有一个更好的算法

我读过:


我们如何对不重复的字符进行排序,然后再对重复的字符进行排序?

您可以使用计数器根据重复的数字跟踪所需的迭代

import string
from collections import Counter

ORDER = {s:i for i, s in enumerate(string.ascii_letters + string.digits)}

def my_sorted(s):

    c = Counter(s)
    res = []
    it = 1

    to_sort = set(c)
    while len(to_sort) > 0:
        res.append(sorted(to_sort ,key=lambda x:ORDER[x]))
        to_sort = [k for k in c if c[k] > it]
        it+=1

    return "-".join(["".join(l) for l in res])
例如:

>>> s="ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-gpwxSVZ-wx-x-x
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'

从@abc的答案中窃取

import string
from collections import Counter

ORDER = {s:i for i, s in enumerate(string.ascii_letters + string.digits)}

def my_sorted(s):

    c = Counter(s)
    res = []

    while c:
        res.append(''.join(sorted(c, key=ORDER.get)))
        c -= Counter(set(c))

    return "-".join(res)
例如:

>>> s="ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-gpwxSVZ-wx-x-x
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'

仍在窃取@abc的设置,但完全不同的解决方案。我附加所需数量的破折号,然后根据1)字符出现的次数和2)aA0顺序对所有内容进行排序

import string
from collections import Counter

ORDER = {s:i for i, s in enumerate(string.ascii_letters + string.digits + '-')}

def my_sorted(s):
    return ''.join(sorted(s + '-' * (max(Counter(s).values()) - 1),
                          key=lambda c, ctr=Counter(): (ctr.update(c) or ctr[c], ORDER[c])))
例如:

>>> s="ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-gpwxSVZ-wx-x-x
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'
>>> s = "ZrXx2VpVJMgPs54SwwxSophZEWvwKUxzqNxaxlgY0T"
>>> my_sorted(s)
'aghlopqrsvwxzEJKMNPSTUVWXYZ0245-gpwxSVZ-wx-x-x'