0

I have a list in python, which I'd like to iterate and capitalize every letter that isn't 'A', so turn this list:

['albert', 'angela', 'leo', 'bridget']

Into:

['aLBERT', 'aNGELa', 'LEO', 'BRIDGET']
jwesonga
  • 4,249
  • 16
  • 56
  • 83
  • I'd suggest you look at Duncan's answer as I believe it would be much better on a large list. In fact, just on your list, his answer is almost 6x faster, as tested w/ the timeit module – pyInTheSky Oct 04 '11 at 15:23
  • @jwesonga: Can you specify what to do with letters 'a' and 'A'? In fact, some answers transform 'Alberta' into 'ALBERTA' while some others transform it into 'aLBERTA'. – Eric O. Lebigot Oct 05 '11 at 07:51
  • also can you say what you want to do with accented letters? – Duncan Oct 05 '11 at 13:08

6 Answers6

4
[''.join(c.upper() if c != 'a' else c for c in word) for word in the_list]
JBernardo
  • 32,262
  • 10
  • 90
  • 115
  • @EOL: I'd argue that a solution using the `map` function could be simpler, though not by much.. – machine yearning Oct 04 '11 at 14:41
  • @machineyearning A lightning strikes a little kitten every time someone says map is better than a comprehension... Just saying – JBernardo Oct 04 '11 at 14:44
  • 1
    @EOL: Simpler would be `[word.upper().replace('A','a') for word in the_list]`. This works as it's ok to convert 'Adam' to 'aDaM'. – Steven Rumbalski Oct 04 '11 at 14:48
  • @StevenRumbalski And to win the code golf challenge I would go further: `eval(str(the_list).upper().replace('A','a'))` :D – JBernardo Oct 04 '11 at 14:50
  • @JBernardo: I see your smiley face. But I want to emphasize my emphasis was on simpler, not shorter. – Steven Rumbalski Oct 04 '11 at 14:55
  • 1
    @StevenRumbalski I know, but not sure if turning "Adam" into "aDaM" is ok or not... – JBernardo Oct 04 '11 at 14:56
  • @Jbernardo: Not sure I understand what you're getting at. Please explain why you don't like using `map` in the place of a comprehension. It seems to me like they do the same thing, but `map` is just a standard higher-level abstraction that is often used for list processing. – machine yearning Oct 04 '11 at 15:17
  • @machineyearning In most cases, map is plain ugly and had it's behaviour changed from Python 2 to 3. Also, comprehensions don't require lambda functions or any function call at all... – JBernardo Oct 04 '11 at 15:26
  • @JBernardo: I see your point, thanks for explaining. This thread helped me see your point: http://stackoverflow.com/questions/1247486/python-list-comprehension-vs-map – machine yearning Oct 04 '11 at 15:39
3

All of the existing answers seem to want to operate on the characters individually. It is simpler and easier just to handle the words as a whole:

>>> the_list = ['albert', 'angela', 'leo', 'bridget']
>>> [ word.upper().replace('A', 'a') for word in the_list]
['aLBERT', 'aNGELa', 'LEO', 'BRIDGET']
Duncan
  • 92,073
  • 11
  • 122
  • 156
  • was just about to post this. I think it's better than the other answer because it has way less calls and no if conditions – pyInTheSky Oct 04 '11 at 15:13
  • 3
    Unless you've got `Albert` and you want it to become `ALBERT` not `aLBERT`. But it's not clear from the example whether uppercase letters are allowed to start with. (And my answer doesn't operate on the characters individually, and even uses less function calls than this one, @pyInTheSky, n+3 rather than n*2, though it doesn't work for non-ASCII characters.) – agf Oct 04 '11 at 16:04
  • very nice, i've used it before but didn't know it was that fast – pyInTheSky Oct 05 '11 at 12:17
1
>>> import re
>>> sl = ['albert', 'angela', 'leo', 'bridget']
>>> [re.sub('[^a]+', lambda m: m.group(0).upper(), s) for s in sl]
['aLBERT', 'aNGELa', 'LEO', 'BRIDGET']
hamstergene
  • 24,039
  • 5
  • 57
  • 72
  • 1
    Maybe it wasn't @EOL. Regex — it depends. On strings of thouzands characters, regex will be few times faster than JBernardo's solution (you can check that with `timeit`). They are also the most flexible, in case the task becomes more complex then just "a or not a". – hamstergene Oct 04 '11 at 20:36
1

This is what str.translate is for:

import string

table = string.maketrans(string.ascii_lowercase.replace('a', ''),
                            string.ascii_uppercase.replace('A', ''))

names = ['albert', 'angela', 'leo', 'bridget']

print [name.translate(table) for name in names]

translate takes a 256 character table, so you use string.maketrans to turn the string constants representing the lowercase and uppercase alphabet into a table. Any letters not appearing in the table are ignored, so removing a and A will uppercase all other letters.

Then just apply the translation table to each name in the list.

It will be faster than iterating over each name and calling upper on every letter but a. While the general Python tools make this easy, this is the tool specifically made for this job.

agf
  • 171,228
  • 44
  • 289
  • 238
  • 1
    Smart but will not work for letters like `áéüâõ` (if that is needed). – JBernardo Oct 04 '11 at 14:00
  • Just out of curiocity, is it OK to change `string.ascii_*` constants? – ronakg Oct 04 '11 at 14:01
  • @RonakG Strings are immutable, you can't change them. All `replace` does is return a new string with substrings replaced. – agf Oct 04 '11 at 14:02
  • @agf it will if the locale is set properly – hamstergene Oct 04 '11 at 14:18
  • @agf the gibberish is the uppercased versions which your terminal does not display properly – hamstergene Oct 04 '11 at 14:26
  • @EugeneHomyakov @JBernardo `u'áéüâõ'.upper()` does work for me with `#coding: latin-1` or `#coding: utf-8`, though `'áéüâõ'.upper()` doesn't. Still, this is clearly a homework assignment or tutorial exercise, and all the examples are ASCII, so it's probably not relevant. – agf Oct 04 '11 at 16:02
0

The inelegant way is simple

  lst = ['albert', 'angela', 'leo', 'bridget']
  lst2 = []

  for wrd in lst:
      newwrd = ''
      for ltr in wrd:
          if ltr != 'a':
              newwrd += ltr.upper()
          else: newwrd += ltr
      lst2.append(newwrd)

However list complrehensions will be more pythonic

lst = ['albert', 'angela', 'leo', 'bridget']
[''.join(ltr.upper() if ltr != 'a' else 'a' for ltr in wrd) for wrd in lst]

This is essentially nested list comprehensions replacing the nested loops. This is a much neater solution and more understandable

A list comprehension is an expression (ltr.upper() if ltr == 'a') followed by "for" and then option if clauses. Here we have two (and I see @JBernardo did the same thing) acting in same way as nested for loops.

I hope that helps explain the differences.

lifeisstillgood
  • 3,265
  • 2
  • 21
  • 22
0

If you want to engage the functional programming paradigm a bit more:

def maybe_upper(c, u):
    return c.upper() if c in u else c

def some_upper(s, u):
    return ''.join(map(lambda c: maybe_upper(c, u), s))

>>> some_upper("wahwahweeeewagh", 'uea')
'wAhwAhwEEEEwAgh'
machine yearning
  • 9,889
  • 5
  • 38
  • 51