如果文本中的任何内容不是字母,请忽略它,不要返回它。
a
是1
,b
是2
,等等。例如:
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)
#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的内置count
和zip
来生成字母及其在字母表中位置之间的映射。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
评论
...为什么要遍历字典而不使用访问器?á,ß,ç,Ø,θ或ж应该发生什么?
在此特定情况下,@ PieterB会忽略这些字母,因为目标是仅获取字母(英语)。
@nexla很抱歉,我看到了代码的作用,但是明确要求始终是拥有好的软件的开始。