0

首先我想提一下,我创建的这个简单脚本可能没有任何现实生活中的应用程序,但我这样做是因为我正在学习并且我在 SO 中找不到任何类似的东西。我想知道可以做些什么来“任意”更改列表中的可迭代字符。

当然tile()是一个我学得相对较快的方便工具,但后来我想如果只是为了踢球,我想格式化(大写)最后一个字符怎么办?或第三,中间的,等等。小写呢?用其他字符替换特定字符?

就像我说的那样,这肯定不是完美的,但可以为像我这样的其他菜鸟提供一些思考的食物。另外,我认为这可以通过数百种方式进行修改,以实现各种不同的格式。

帮助我改进我刚刚做的事情怎么样?如何让它更精简和平均?检查风格、方法、效率等...

它是这样的:

words = ['house', 'flower', 'tree']  #string list

counter = 0                          #counter to iterate over the items in list
chars = 4                            #character position in string (0,1,2...)

for counter in range (0,len(words)): 
    while counter < len(words):
        z = list(words[counter])     # z is a temp list created to slice words
        if len(z) > chars:           # to compare char position and z length
            upper = [k.upper() for k in z[chars]] # string formatting EX: uppercase
            z[chars] = upper [0]     # replace formatted character with original
            words[counter] = ("".join(z)) # convert and replace temp list back into original word str list
            counter +=1
        else:
            break

print (words)

['housE', 'flowEr', 'tree']
4

4 回答 4

2

有比我更好的 Pythonistas,但这里有一个尝试:

[''.join(
      [a[x].upper() if x == chars else a[x]
          for x in xrange(0,len(a))]
    )
    for a in words]

另外,我们说的是程序员的第四,对吧?其他人都称之为第五,是吗?

于 2012-12-06T00:14:33.433 回答
2

我认为您所说的一般情况是一种方法,给定一个字符串和一个索引,返回该字符串,并根据某些规则转换索引字符。

def transform_string(strng, index, transform):
    lst = list(strng)
    if index < len(lst):
        lst[index] = transform(lst[index])
    return ''.join(lst)


words = ['house', 'flower', 'tree']
output = [transform_string(word, 4, str.upper) for word in words]

为了使其更加抽象,您可以拥有一个返回方法的工厂,如下所示:

def transformation_factory(index, transform):
    def inner(word):
        lst = list(word)
        if index < len(lst):
            lst[index] = transform(lst[index])
    return inner
transform = transformation_factory(4, lambda x: x.upper())
output = map(transform, words)
于 2012-12-06T00:35:13.757 回答
2

这在某种程度上是两者的结合(所以对它们都+1 :))。主函数接受一个列表、一个任意函数和要作用的字符:

In [47]: def RandomAlter(l, func, char):
    return [''.join([func(w[x]) if x == char else w[x] for x in xrange(len(w))]) for w in l]
   ....:

In [48]: RandomAlter(words, str.upper, 4)
Out[48]: ['housE', 'flowEr', 'tree']

In [49]: RandomAlter([str.upper(w) for w in words], str.lower, 2)
Out[49]: ['HOuSE', 'FLoWER', 'TReE']

In [50]: RandomAlter(words, lambda x: '_', 4)
Out[50]: ['hous_', 'flow_r', 'tree']

该函数RandomAlter可以重写为这样,这可能会使其更加清晰(它利用称为列表推导的功能来减少所需的代码行数)。

def RandomAlter(l, func, char):
    # For each word in our list
    main_list = []
    for w in l:
        # Create a container that is going to hold our new 'word'
        new_word = []
        # Iterate over a range that is equal to the number of chars in the word
        # xrange is a more memory efficient 'range' - same behavior
        for x in xrange(len(w)):
            # If the current position is the character we want to modify
            if x == char:
                # Apply the function to the character and append to our 'word'
                # This is a cool Python feature - you can pass around functions
                # just like any other variable
                new_word.append(func(w[x]))
            else:
                # Just append the normal letter
                new_word.append(w[x])

        # Now we append the 'word' to our main_list. However since the 'word' is
        # a list of letters, we need to 'join' them together to form a string
        main_list.append(''.join(new_word))

    # Now just return the main_list, which will be a list of altered words
    return main_list
于 2012-12-06T00:44:35.520 回答
2

对您的代码的一些评论:

for counter in range (0,len(words)):     
while counter < len(words):

while除非您在循环下缩进循环,否则这不会编译for。而且,如果你这样做,内循环将完全搞砸外循环的循环计数器。最后,您几乎从不想在 Python 中维护显式循环计数器。你可能想要这个:

for counter, word in enumerate(words):

下一个:

z = list(words[counter])     # z is a temp list created to slice words

您已经可以对字符串进行切片,就像切片列表一样,所以这是不必要的。

下一个:

    upper = [k.upper() for k in z[chars]] # string formatting EX: uppercase

这是一个不好的变量名称,因为有一个名称完全相同的函数——您在同一行调用它。

同时,你定义事物的方式,z[chars]是一个角色,一个副本words[4]。您可以在 Python 中迭代单个字符,因为每个字符本身就是一个字符串。但这通常是没有意义的——<code>[k.upper() for k in z[chars]] 与[z[chars].upper()].

    z[chars] = upper [0]     # replace formatted character with original

所以你只想要 1 个字符的列表来从中取出第一个字符……为什么一开始就让它成为一个列表?只需将最后两行替换为z[chars] = z[chars].upper().

else:
    break

这将在第一个短于长度 4 的字符串上停止,而不是仅仅跳过短于长度 4 的字符串,这就是你想要的。这么说的方式是continue,不是break。或者,更好的是,从列表的末尾掉下来。在某些情况下,没有 a 很难写continue,但在这种情况下,它很容易——它已经在循环的末尾,实际上它在一个else:没有其他内容的内部,所以只需删除这两行。

很难upper说你的循环是错误的,因为如果你不小心调用upper了两次,它看起来就像你调用了一次一样。将 更改upperchr(ord(k)+1),它将任何字母替换为下一个字母。然后尝试:

words = ['house', 'flower', 'tree', 'a', 'abcdefgh']

您会注意到,例如,您得到'flowgr'的不是'flowfr'.

您可能还想添加一个变量来计算您通过内部循环的次数。它应该只是len(words)时间,但实际上是len(words) * len(words)如果你没有简短的话,或者len(words) * len(<up to the first short word>)如果你有的话。你让计算机做很多额外的工作——如果你有 1000 个单词,它必须做 1000000 个循环而不是 1000 个。从技术上讲,你的算法是 O(N^2),即使它只需要为 O(N)。

把它们放在一起:

words = ['house', 'flower', 'tree', 'a', 'abcdefgh']  #string list
chars = 4                            #character position in string (0,1,2...)

for counter, word in enumerate(words): 
    if len(word) > chars:           # to compare char position and z length
        z = list(word)
        z[chars] = chr(ord(z[chars]+1) # replace character with next character
        words[counter] = "".join(z)    # convert and replace temp list back into original word str list

print (words)

这与您的原始代码做同样的事情(除了使用“下一个字符”而不是“大写字符”),没有错误,计算机工作少得多,并且更容易阅读。

于 2012-12-06T01:13:23.213 回答