【问题标题】:How to split a list based on whether the elements were next to each other in the list they came from?如何根据元素在它们来自的列表中是否彼此相邻来拆分列表?
【发布时间】:2017-12-22 23:25:38
【问题描述】:

我正在学习 MIT 主要 Python 课程的第 3 题,并且我有一个公认的冗长的脚本,感觉好像快要接近了。我需要打印 s 的最长子字符串,其中字母按字母顺序出现。我能够提取出与其旁边的字符按字母顺序排列的任何字符。我需要看到的是:

输入:'aezcbobobegghakl'

需要的输出:'beggh'

我的输出:['a', 'e', 'b', 'b', 'b', 'e', 'g', 'g', 'a', 'k']

我的代码:

s = 'aezcbobobegghakl'

a = 'abcdefghijklmnopqrstuvwxyz'

len_a = len(a)
len_s = len(s)

number_list = []
letter_list = []

for i in range(len(s)):
    n = 0
    letter = s[i+n]
    if letter in a:
        number_list.append(a.index(letter))
        n += 1

print(number_list)

for i in number_list:
    letter_list.append(a[i])

print(letter_list)

index_list = []
for i in range(len(letter_list)):
    index_list.append(i)

print(index_list)

first_check = []

for i in range(len(letter_list)-1):
    while number_list[i] <= number_list[i+1]:
        print(letter_list[i])
        first_check.append(letter_list[i])
        break

print(first_check)

我知道有很多更短且完全不同的方法可以解决问题,但为了我的理解,是否有可能完成这段代码以获得我正在寻找的输出?或者这只是我挖的一个失败的原因兔子洞?

【问题讨论】:

    标签: python python-3.x list loops


    【解决方案1】:

    我会构建一个生成器来输出所有字符的运行,例如l[i] &gt;= l[i-1]。然后找到最长的那些运行。类似的东西

    def runs(l):
        it = iter(l)
        try:
            run = [next(it)]
        except StopIteration:
            return
        for i in it:
            if i >= run[-1]:
                run.append(i)
            else:
                yield run
                run = [i]
        yield run
    
    def longest_increasing(l):
        return ''.join(max(runs(l), key=len))
    

    编辑:代码注释

    for i in range(len(s)):
        n = 0
        letter = s[i+n]
        if letter in a:
            number_list.append(a.index(letter))
            n += 1
    

    正在获取每个字母的“数字值”。您可以使用ord 函数来简化此操作

    number_list = [ord(c) - 97 for c in s if c.islower()]
    

    你从不使用index_list,你永远也不应该使用。查看enumerate 函数。

    first_check = []
    
    for i in range(len(letter_list)-1):
        while number_list[i] <= number_list[i+1]:
            print(letter_list[i])
            first_check.append(letter_list[i])
            break
    

    这部分没有多大意义。你break 每次都退出while 循环,所以它基本上是if。您无法跟踪超过一次的运行。您在这里没有将字符运行相互比较的机制。我认为您可能正在尝试做类似的事情

    max_run = []
    for i in range(len(letter_list)-1):
        run = []
        for j in range(i, len(letter_list)):
            run.append(letter_list[j])
            if letter_list[j] > letter_list[j+1]:
                break
        if len(run) > len(max_run):
            max_run = run
    

    (免责声明:我很确定以上内容有所偏差,但应该是说明性的)。以上可以通过很多方式进行改进。请注意,它循环最后一个字符多达len(s) 次,使其成为n**2 解决方案。另外,我不确定您为什么需要number_list,因为可以直接比较字符串。

    【讨论】:

    • 我已经看到了这个解决方案,但我的特殊问题是,按照我给出的代码的逻辑流程,是否有可能完成它以获得所需的结果?我知道它可以更好,我只是想了解如何让我的工作。
    • 感谢您的详尽解释!非常感谢。
    【解决方案2】:

    一个简单的递归方法怎么样:

    data = 'ezcbobobegghakl'
    words=list(data)
    
    string_s=list(map(chr,range(97,123)))
    
    final_=[]
    def ok(list_1,list_2):
    
        if not list_1:
            return 0
        else:
            first = list_1[0]
            chunks = list_2[list_2.index(first):]
    
            track = []
    
            for j, i in enumerate(list_1):
    
                if i in chunks:
                    track.append(i)
                    chunks=list_2[list_2.index(i):]
    
                else:
                    final_.append(track)
                    return ok(list_1[j:],list_2)
                final_.append(track)
    
    
    
    print(ok(words,string_s))
    print(max(final_,key=lambda x:len(x)))
    

    输出:

    ['b', 'e', 'g', 'g', 'h']
    

    【讨论】:

      【解决方案3】:

      您可以找到输入字符串的所有子字符串的列表,然后查找所有按字母顺序排序的字符串。判断一个字母是按字母顺序排序的,把原字符串按在字母表中的位置排序,然后看看最后的字符串是否等于原字符串:

      from string import ascii_lowercase as l
      s = 'aezcbobobegghakl'
      substrings = set(filter(lambda x:x, [s[i:b] for i in range(len(s)) for b in range(len(s))]))
      final_substring = max([i for i in substrings if i == ''.join(sorted(list(i), key=lambda x:l.index(x)))], key=len)
      

      输出:

      'beggh'
      

      【讨论】:

        【解决方案4】:

        这是完成工作的一种方式:

        s = 'aezcbobobegghakl'
        l = list(s)
        run = []
        allrun = []
        element = 'a'
        
        for e in l:
            if e >= element:
                run.append(e)
                element = e
            else:
                allrun.append(run)
                run = [e]
                element = e
        
        lengths = [len(e) for e in allrun]
        result = ''.join(allrun[lengths.index(max(lengths))])
        

        “run”基本上是不间断的运行;当您添加比以前看到的更大的元素时,它会不断增长(“b”大于“a”,只是字符串比较),并重置其他。

        “allrun”包含所有“run”,如下所示:

        [['a', 'e', 'z'], ['c'], ['b', 'o'], ['b', 'o'], ['b', 'e', 'g', 'g', 'h']]
        

        “result”最终选择“allrun”中最长的“run”,并合并为一个字符串。


        关于您的代码:

        这是非常非常低效的,我不会继续它。我会采用已发布的解决方案之一。

        你的 number_list 可以写成 [a.index(_) for _ in s],一个班轮。

        您的 letter_list 实际上只是列表,而您为此使用了循环!

        您的 index_list,它甚至可以做什么?它等效于 range(len(letter_list)),那么您在循环中使用 append 的目的是什么?

        最后,你编写循环的方式让我想起了 matlab。您可以只迭代列表的元素,无需迭代索引并获取列表中的相应元素。

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 2015-09-11
          • 2019-08-19
          • 2011-01-17
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多