0

I've made a hasher. It works and it's really simple. I made one for fun and I thought that the code is way too long. It's over 1000 lines long and it's so simple. I just want to shorten it down. Here's how I did the code:

wordorg = raw_input("Enter a word here: ")

## Checking if what you typed is correct
if len(wordorg) <= 10 and len(wordorg) > 1 and wordorg.isalpha():
  ## Comparison (JESUS THIS IS A LONG PIECE OF CODE)
  print "Your original word was: " + wordorg
  word = wordorg.lower()
  if len(word) >= 1:
    if word[0] == "a":
        one = a
    if word[0] == "b":
        one = b
    if word[0] == "c":

Bla bla bla, you get the idea, it goes like that. When it reaches Z

    if word[0] == "z":
      one = z
    if len(word) >= 2:
      if word[1] == "a":

And it goes on. My question is, how can I shorten my code?

EDIT: The integers a, b, c are defined like this:

a = 2
b = 3
c = 5

and so on.

  • 1
    How are `a, b, c, ...` variables defined? – Eric Duminil Nov 21 '17 at 12:41
  • I don't understand, what you exactly want to achieve, but you may want to split the word into a list and cycle through this list instead. https://stackoverflow.com/questions/113655/is-there-a-function-in-python-to-split-a-word-into-a-list#113662 – Mr. T Nov 21 '17 at 12:42
  • 1
    @Piinthesky: A Python string can be used as a list of characters, without converting anything. `'abcdef'[2:5] # 'cde'` – Eric Duminil Nov 21 '17 at 12:49
  • Yup. Thought about it only after I sent my comment that one could also write `for char in wordorg` avoiding any conversion. – Mr. T Nov 21 '17 at 12:53

3 Answers3

2

You could use a dict to split your line count by 26:

>>> import string
>>> translate = {l:i for i,l in enumerate(string.ascii_lowercase, 1)}
>>> translate
{'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}

Now, all you need is a dict lookup instead of 26 ifs:

>>> word='something'
>>> translate[word[0]]
19
>>> translate[word[1]]
15

You could replace the 1, 2, ... values with the ones defined as a, b, ... in your code.

If you want to do it for every letter, simply use a list comprehension:

>>> [translate[letter] for letter in word]
[19, 15, 13, 5, 20, 8, 9, 14, 7]

You now have a list of integers, ready for further processing!

Eric Duminil
  • 52,989
  • 9
  • 71
  • 124
2

I don't know where you go exactly from the code snippet you gave but I suggest to start from:

[1+ord(chr)-ord('a') for chr in wordorg]

ord is a function returning the ascii code of a character (a=97, b=98, etc.). So 1+ord(chr)-ord('a') will return 1 for 'a', 2 for 'b', etc.

It seems more interesting not to use a dictionary in your hash function, since a dictionary itself is a hash table.

papagaga
  • 1,108
  • 8
  • 14
0

I think this does what you're looking for. What I did is build a loop that runs over your word, so it can compare letter by letter. The second loop goes over the letters of the alphabet and if your word letter has a match, this is stored in the array results. This array counts the occurrences of each letter. If you want you can replace the print statement with writing to a file. There is also no need to restrict your code to run on short words anymore.

import string

alphabet = string.ascii_lowercase
results = [0] * len(alphabet) # array to count occurrences of letters
wordorg = raw_input("Input word here: ")

print alphabet
if wordorg.isalpha():

    for i in range(len(wordorg)):
            for j in range(len(alphabet)):
                if (wordorg[i].find(alphabet[j])!=-1):
                    results[j] += 1

        # print results



    for i in range(len(alphabet)):
        if (results[i]>0):
            print "There are %d occurrences of the letter %s" %(results[i], alphabet[i])
  • It looks like you implemented an inefficient [`Counter`](https://docs.python.org/3/library/collections.html#collections.Counter) – Eric Duminil Nov 21 '17 at 13:14