如果文本中的任何内容不是字母,请忽略它,不要返回它。

a1b2,等等。

例如:

alphabet_position("The sunset sets at twelve o' clock.")应该返回
“ 20 8 5 19 21 14 19 5 20 19 5 20 19 1 20 20 23 5 12 22 5 15 3 12 15 3
11“作为字符串。


这是我的幼稚解决方案,下面的代码在python 2.7中

def alphabet_position(text):
    dictt = {'a':'1','b':'2','c':'3','d':'4','e':'5','f':'6','g':'7','h':'8',
    'i':'9','j':'10','k':'11','l':'12','m':'13','n':'14','o':'15','p':'16','q':'17',
    'r':'18','s':'19','t':'20','u':'21','v':'22','w':'23','x':'24','y':'25','z':'26'
    }
    arr = []
    new_text = text.lower()
    for i in list(new_text):
        for k, j in dictt.iteritems():
            if k == i:
                arr.append(j)
    return ' '.join(arr)


评论

...为什么要遍历字典而不使用访问器?

á,ß,ç,Ø,θ或ж应该发生什么?

在此特定情况下,@ PieterB会忽略这些字母,因为目标是仅获取字母(英语)。

@nexla很抱歉,我看到了代码的作用,但是明确要求始终是拥有好的软件的开始。

#1 楼

首先,您无需对字母及其在字母表中的位置进行硬编码-您可以使用string.ascii_lowercase

此外,您不必在list()上调用new_text-您可以只是逐个字符地对其进行迭代。

然后,如果我们要在字母和字母索引之间构造一个映射(借助enumerate()),该怎么办。然后,使用列表推导创建一个数字数组,然后我们将其连接以产生结果:

from string import ascii_lowercase


LETTERS = {letter: str(index) for index, letter in enumerate(ascii_lowercase, start=1)} 

def alphabet_position(text):
    text = text.lower()

    numbers = [LETTERS[character] for character in text if character in LETTERS]

    return ' '.join(numbers)


评论


\ $ \ begingroup \ $
[文字中的字符的LETTERS.get(character)]会更好吗?另外,如果我们要优化速度,我认为对于长文本来说,最好预先生成一个大写和小写字母的字典,然后节省不对每个字母执行lower()的时间(毕竟,本质上是对字符串进行两次迭代,一次将所有内容都转换为小写,然后再次转换为累赘。
\ $ \ endgroup \ $
–累计
17-12-27 17:50

\ $ \ begingroup \ $
@积累我喜欢不降低弦的想法,经典的时空牺牲,谢谢!
\ $ \ endgroup \ $
– alecxe
17年12月27日在18:06

\ $ \ begingroup \ $
次要nitpick:数字可能是生成器:数字=(如果字母中的字符,则为文本中的字符的[LETTERS [character])
\ $ \ endgroup \ $
–埃里克·杜米尼尔(Eric Duminil)
17年12月27日在21:32

\ $ \ begingroup \ $
@EricDuminil可以,但是上次我检查时,加入列表比加入生成器要快一些,因为在cPython中str.join首先在内部将生成器消耗到列表中。它需要这样做才能知道为字符串分配多少空间。参见例如stackoverflow.com/a/37782238。
\ $ \ endgroup \ $
–地狱
17/12/28在11:04



#2 楼

与@alecxe提出的建议略有不同(嗯,^ _ ^并没有太大不同),是使用Python的内置countzip来生成字母及其在字母表中位置之间的映射。

from itertools import count
from string import ascii_lowercase


def letter_indexes(text):
    letter_mapping = dict(zip(ascii_lowercase, count(1)))
    indexes = [
      letter_mapping[letter] for letter in text.lower() 
      if letter in letter_mapping
    ]

    return ' '.join(str(index) for index in indexes)


#3 楼

如果您只关心ASCII字符,则还可以利用以下事实:它们的字符代码从'a'的97连续到'z'的122,然后执行类似

def alphabet_position(text):
    nums = [str(ord(x) - 96) for x in text.lower() if x >= 'a' and x <= 'z']
    return " ".join(nums)


但是,请注意,它可能给人的印象是比@alecxe的解决方案要快,但实际上,对于长输入字符串来说,它要慢得多,因为在每个输入字符上调用str()ord()会更慢比字典查询。对于短输入字符串的重复调用,可以提供相同甚至更好的性能,但这只是因为letters字典是在@alecxe函数的每次调用上重新构建的,因此很容易更改。 (UPD 。:不,不再)。如果那很重要。

评论


\ $ \ begingroup \ $
关于字母字典在每次调用时都会重新初始化的要点-移至适当的“常数”。谢谢!
\ $ \ endgroup \ $
– alecxe
17年12月27日在3:58

\ $ \ begingroup \ $
我懒于编写速度测试,但我想字节(...生成字节...).encode('ascii')比在每个字符上调用str都快。
\ $ \ endgroup \ $
– wvxvw
17年12月27日在6:23



\ $ \ begingroup \ $
ord(x)中的幻数-96很有趣-使用ord(x)-ord('a')+ 1或offsetA = ord('a')-1 ord(x)-offsetA 。
\ $ \ endgroup \ $
–灰胡子
19年3月16日在5:35

#4 楼

最终,经过大量的脑筋急转弯,我找到了一种避免调用ord()的方法,该方法显然很昂贵。以下是测试代码和结果:

from timeit import timeit
from itertools import count
from string import ascii_lowercase


def alphabet_position_Headcrab(text):
    nums = [str(ord(x) - 96) for x in text.lower() if x >= 'a' and x <= 'z']
    return " ".join(nums)


def alphabet_position_wvxvw(text):
    result, i = [32, 32, 32] * len(text), 0
    for c in bytes(text.lower(), 'ascii'):
        if 97 <= c < 106:
            result[i] = c - 48
            i += 2
        elif 106 <= c < 116:
            result[i] = 49
            result[i + 1] = c - 58
            i += 3
        elif 116 <= c <= 122:
            result[i] = 50
            result[i + 1] = c - 68
            i += 3
    return bytes(result[:i-1])


def letter_indexes(text):
    text = text.lower()

    letter_mapping = dict(zip(ascii_lowercase, count(1)))
    indexes = [
      letter_mapping[letter] for letter in text
      if letter in letter_mapping
    ]

    return ' '.join(str(index) for index in indexes)


def test(f):
    data = "The sunset sets at twelve o' clock."
    for _ in range(5):
        f(data)
        data = data + data


def speed_compare():
    results = {
        'wvxvw': timeit(
            'test(alphabet_position_wvxvw)',
            setup='from __main__ import (test, alphabet_position_wvxvw)',
            number=10000,
        ),
        'Headcrab': timeit(
            'test(alphabet_position_Headcrab)',
            setup='from __main__ import (test, alphabet_position_Headcrab)',
            number=10000,
        ),
        'MrGrj': timeit(
            'test(letter_indexes)',
            setup=(
                'from __main__ import (test, letter_indexes)\n'
                'from itertools import count\n'
                'from string import ascii_lowercase\n'
            ),
            number=10000,
        )
    }
    for k, v in results.items():
        print(k, 'scored', v)


运行speed_compare()会给出以下输出:

wvxvw scored 1.7537127458490431
Headcrab scored 2.346936965826899
MrGrj scored 2.2078608609735966


评论


\ $ \ begingroup \ $
我想这是解决问题的方法,但是按照我的口味,对于相对简单的问题来说,它太模棱两可了。
\ $ \ endgroup \ $
–丹尼尔(Daniel)
17年12月27日在10:01

\ $ \ begingroup \ $
@alecxe提供的解决方案不是更快吗?当我在“ Anna Karenina”的英文翻译中进行检查时,它比我的代码快大约3倍,据估计,它也应该比您的代码快。
\ $ \ endgroup \ $
–头枕
17/12/27在10:56

\ $ \ begingroup \ $
@Headcrab我不知道如何测量它:它具有不平凡的设置代码,这也是解决问题的一部分。如果我在每个测试中都包含此设置代码,那么它与MrGrj的代码不会有太大不同,否则,这会感到不公平,因为解决该问题所需的一些工作是在测试之外完成的。
\ $ \ endgroup \ $
– wvxvw
17年12月27日在11:15

\ $ \ begingroup \ $
您提出了一种替代解决方案,但尚未检查代码。请编辑以显示问题代码的哪些方面促使您编写此版本,以及对原始版本进行了哪些改进。也许(重新)阅读“如何回答”是值得的。
\ $ \ endgroup \ $
– Toby Speight
19年5月30日在12:11

#5 楼

这个简单问题的所有库要求似乎都很复杂。我不精通Python语法,但我知道可以做到。让我用伪代码解释一下(语法可以由您查询):已经是它们的位置...因此,“ a”的位置为0(因为Python索引是基于0的;如果您不喜欢它,则可以在结果中加1以显示从1开始计数的结果)
(小写或大写字母都没关系,因为您要看的是它们的位置,而不是alphabet[]="'a', 'b',....'z'"的值)
获取要比较的字符串及其长度:ord
长度,迭代并找到字符串(例如len(astring))中的字符(例如achar)。 astring循环或一些神奇的python 1行语句,例如:for
如果使用1行语句而不是循环,则可能必须将它们加载到另一个列表中并在其中循环。不确定,我喜欢for achar in astring循环,所以...
for循环内,检查每个for的索引位置(例如achar是否为循环计数器),然后将该位置装入新数组(定义一个空数组首先在循环外部)说,“ chr(x) == astring[i]
循环结束后,i应该具有每个匹配char的位置(从0开始)。如果您希望基于1的位置,则可以在每个值上加1。

对不起,我无法编写完整的代码,主要是因为我的语法知识在Python中还不是很好,但是逻辑应该有意义,对吧?

评论


\ $ \ begingroup \ $
欢迎使用CR Tony,这个答案看起来像是在审查代码,而且您的答案不可读。请参阅编辑帮助。
\ $ \ endgroup \ $
–bhathiya-perera
19 Mar 16 '19在0:44



\ $ \ begingroup \ $
[上面提出的]逻辑应该是合理的,也许应该是合理的:在我看来,事实并非如此。优先考虑可读性,避免公开代码。当出现问题时,您会为速度而烦恼,但要反复进行操作,然后在字符串中找到字符[…]似乎需要它。 (等等,我什至不明白您的建议是什么:achar将会是什么,以及如何将其有助于所需的结果?)
\ $ \ endgroup \ $
–灰胡子
19年3月16日在5:54