The Python Challenge – 2

This challenge is interesting in that it is confirming to me how inexperienced my programming actually is. I can get to the solution but the answer shows how limited I am. Here is my solution to 2 (I’d copied and pasted the text from the source to a document 2_message.txt.)

My Python 2.7 Solution

# find rare characters in the mess below:

maxoccurence = 1 #how many do I think is rare?

# load up the file
s = open(r"2_message.txt", "r").read()
#find the unique characters
uniqueones = set(s)

#find the rare characters (<= maxoccurence) and their position
rareones = []
for one in uniqueones:
position = []
if s.count(one) <=1:
position.append(one)
position.append(s.index(one))
rareones.append(position)


#rareones is now a multi dimensional list with the character and its position
from operator import itemgetter
solution = ""
for final in sorted(rareones, key=itemgetter(1)):
solution += final[0]
print solution

But here is the first of the suggested solutions

import collections
data = ''.join([line.rstrip() for line in open('2_message.txt')])
OCCURRENCES = collections.OrderedDict()
for c in data: OCCURRENCES[c] = OCCURRENCES.get(c, 0) + 1
avgOC = len(data) // len(OCCURRENCES)
print ''.join([c for c in OCCURRENCES if OCCURRENCES[c] < avgOC])

I want to understand this! So I spend as much time working it out as I do solving the first problem.  This is a great way of learning. I have had to learn what a Dictionary is in python (a sort of associative 2 dimensional array).  Link this to the collections library and you have got something pretty powerful.
The code appears to

  1. Load the data in to a massive string, removing the carriage returns.
  2. Make a container "Dictionary" for the characters
  3. Whiz through the massive string using the character as a key and simply adding 1 to the number attached to the key.  
  4. Getting the integer (floor) average (//) for each letter if they were distributed evenly.
  5. Concatenating all the items in the Dictionary that are less frequent than the average

This is actually not that different to what I did!!!  Just much more efficient.

[c for c in OCCURRENCES if OCCURRENCES[c] < avgOC]

Is very clever.  It is one line that only outputs a string if the occurrences are less than average.  I am still wrapping my head around it.

My Python 3.2.3 Solution

# find rare characters in the mess below:

# official version
import collections
data = ''.join([line.rstrip() for line in open('2_message.txt')])
OCCURRENCES = collections.OrderedDict()
for c in data: OCCURRENCES[c] = OCCURRENCES.get(c, 0) + 1
# avgOC = len(data) // len(OCCURRENCES)
avgOC = 1
print (''.join([c for c in OCCURRENCES if OCCURRENCES[c] == avgOC]) )

This just needed the modification to "Print" though I did find on python 3 it didn't run because there was no collections library.