Return characters in a string in alphabetical order Problem


  
  Take a string and return all input characters in alphabetical order
  Assume that no numbers or punctuation will be used
  For the same character, uppercase characters should be returned before lowercase characters
  Do not use the sorted helper method
  Do not use any libraries that are not included with Python 3.6.1
  


For example, alphabetize(HelLo) should return eHLlo

Approach


Create a 26-element list. This list will represent the counts (uppercase 
and lowercase) of the different alphabetical characters seen via a dictionary
Iterate through the characters in the input string


Get the index for each character by subtracting the int values 
of the lowercase character from the int value of a
Get the existing count for that index &amp; case from the counts 
dictionary
Increment the count by 1

Initialize the return string
Iterate through each element in the list


For each dictionary / element, get the character, and get the
uppercase and lowercase counts
Add the uppercase characters to the return string
Add the lowercase characters to the return string

Return the alphabetized string


Implementation Discussion

I know the 'Pythonic' way to accomplish this is something like 
''.join(sorted(myString)).

However, as somebody trying to learn Python, I wanted to use this exercise
to learn more about strings and characters in Python (for example) 
vs. Googling a one-liner (not that there's anything wrong with that).

Things I'm concerned about:


Should this be a class? Or is it ok as a standalone method? (As 
somebody that is more comfortable in Java, things that aren't in classes
make me irrationally uneasy.)
Speaking of which, there's a decent amount of stuff going on in this 
method, should I break it up? 


If I decide to break it up, what's the right way of 'showing' that 
some functions are only going to be used by another function? 
I think Python doesn't really have a concept of private vs. 
public so do I _(some_method_name) here?

What other 'Pythonic' elements am I missing (again, aside from using 
the sorted method)?


Implementation



def alphabetize(value):
    uppercase_key = 'uppercase'
    lowercase_key = 'lowercase'

    character_counts = []
    for i in range(26):
        character_counts.append({uppercase_key: 0, lowercase_key: 0}.copy())

    for character in value:
        index = ord(character.lower()) - ord('a')
        counts = character_counts[index]
        key = uppercase_key if character.isupper() else lowercase_key

        count = counts[key]
        counts[key] = count + 1

    alphabetized = ''
    for index, counts in enumerate(character_counts):
        character = chr(ord('a') + index)
        uppercase_counts = counts[uppercase_key]
        lowercase_counts = counts[lowercase_key]
        for i in range(uppercase_counts):
            alphabetized += character.upper()
        for i in range(lowercase_counts):
            alphabetized += character

    return alphabetized
What other 'Pythonic' elements am I missing (again, aside from using the sorted method)?


If you want to more heavily use the standard library, you can use a collections.Counter along with the alphabet constants string.ascii_uppercase and string.ascii_lowercase.

Things are also simpler if you store the counts in a dict (map) instead of the implicit map-by-ord()-value that you're currently using. The ordering of the counts doesn't really matter, just the order in which you output them.

from collections import Counter
from itertools import chain
import string


def alphabetize(s):
    counts = Counter(s)

    return ''.join(
        char * counts[char]
        for char in chain(*zip(string.ascii_uppercase, string.ascii_lowercase))
    )




The counts = Counter(s) line does essentially this:

counts = collections.defaultdict(int)

for char in s:
    counts[char] += 1


where the defaultdict (a handy class) is a dict that auto-initializes values based on the constructor you pass in, instead of throwing an exception for missing keys.

The chain(*zip(...)) is zipping together the uppercase and lowercase alphabets, then flattening them via chain() into a single list, ['A', 'a', 'B', ...].




  Should this be a class?


Nope. This makes sense as a function in Python since it has no external state.


  As somebody that is more comfortable in Java, things that aren't in classes make me irrationally uneasy.


Java ties files to classes, but each Python file is already a module, which is a good level of encapsulation. As a very rough rule, avoid classes in Python except when you want to hold shared state, in which case class away. Or, at least, don't reach first for classes.