Python Forum
Sorting by average ascii value
Thread Rating:
  • 0 Vote(s) - 0 Average
  • 1
  • 2
  • 3
  • 4
  • 5
Sorting by average ascii value
#1
Hey, I have a question in which I need to sort some stuff without using sort/sorted.
I need to do:
1.Write a code which receives words in a list till it get "stop".
2. Afterwards, print the list ( not included stop )
3. Afterwards, sort it lexicography and print again.
4. Afterwards, sort it by length and print again.
5. Lastly, sort it by average ascii value and print again.

I did 1, 2, 3, 4
only 5 is a little problematic.
My code ( Till the average ascii value, it works good, on that it crashes, ill write the error ):
def word_amount_to_list():
    empty_list = []
    while True:
        phrase = input("Please enter your word: ")
        empty_list.append(phrase)
        if phrase == "stop":
            empty_list.remove("stop")
            break
    return empty_list


word = word_amount_to_list()
print(f"List not sorted: {word}")


def lexicography_list():
    x = len(word)
    for i in range(x-1, -1, -1):
        for j in range(i):
            if word[j] > word[j + 1]:
                word[j], word[j + 1] = word[j + 1], word[j]
    return word


lex_list = lexicography_list()
print(f"List sorted by alphabet: {lex_list}")


def sorting_by_length(lst):
    x = len(lst)
    for i in range(x - 1, -1, -1):
        for j in range(i):
            if len(word[j]) > len(word[j + 1]):
                word[j], word[j + 1] = word[j + 1], word[j]
    return word


length_list = sorting_by_length(word)
print(f"List sorted by length: {length_list}")
Till this it works.
Now it wont work:
def sorting_by_ascii_average(lst):
    x = len(word)
    for i in range(x - 1, -1, -1):
        for j in range(i):
            if (ord(word[j])) > (ord(word[j + 1])):
                word[j], word[j + 1] = word[j + 1], word[j]
    return word


average_ascii = sorting_by_ascii_average(word)
print(f"List sorted by average ascii: {average_ascii}")
output: ( If I do single letter, which works: )
Please enter your word: a
Please enter your word: A
Please enter your word: K
Please enter your word: stop
List not sorted: ['a', 'A', 'K']
List sorted by alphabet: ['A', 'K', 'a']
List sorted by length: ['A', 'K', 'a']
List sorted by average ascii: ['A', 'K', 'a']

Process finished with exit code 0
output: (if I dont do single letters - not working the ascii )
Please enter your word: hello
Please enter your word: my
Please enter your word: dear
Please enter your word: blabla
Please enter your word: stop
List not sorted: ['hello', 'my', 'dear', 'blabla']
List sorted by alphabet: ['blabla', 'dear', 'hello', 'my']
List sorted by length: ['my', 'dear', 'hello', 'blabla']
Traceback (most recent call last):
  File "C:\Users\bensh\NewSapirCourse\Sapir_Lesson4\Sorting\Sort-5.py", line 25, in <module>
    average_ascii = sorting_by_ascii_average(word)
  File "C:\Users\bensh\NewSapirCourse\Sapir_Lesson4\Sorting\Sort-5.py", line 20, in sorting_by_ascii_average
    if (ord(word[j])) > (ord(word[j + 1])):
TypeError: ord() expected a character, but string of length 5 found

Process finished with exit code 1
It works only if I put in a list single letters.
I thought about adding sum to the ords, wont work also.
Tried maybe with ord(word[i][j]) and to the other one also, but didnt work either.
I Thought in order to solve this, I need 2 definitions:
1. gets the list and count the ascii value of each letter and then sums it.
2. sort it afterwards

problem is, I dont know how to do that lol.... the ascii are the one i am most weak at... I never use it, but I have to use them in the question...

I will be happy to get some tip in order to answer it, not an answer, just a tip, which function to use, 2 definitions? if yes, what to do on each and such...
Reply
#2
Even if you can't use sort/sorted you should still use their ideas. With sort/sorted you can specify a key which takes the thing you want to sort and returns a value appropriate for sorting.
You should do the same thing. Write one sorting function and pass a sorting key. This would not only result in less and simpler code, but it would fix your problem.

Your problem is you are mixing together your sort and your comparison when you do the ascii average sorting.
def sorting_by_ascii_average(lst):
    x = len(word)
    for i in range(x - 1, -1, -1):   # What is "word"?  It is not defined in this function.  x should be the length of lst
        for j in range(i):
            if (ord(word[j])) > (ord(word[j + 1])):  # This comparison is not valid for many reasons.  It does not compare the average ascii value
                word[j], word[j + 1] = word[j + 1], word[j]
    return word  #  Again, what is word??
Nowhere in this code is there something that computes the average ascii value. If you use my suggestion for a sort key, you can isolate computing the key value from the sort and this problem magically vanishes. If you insist on rewriting the sort function for each sort, you still need to write a key function or add code to compute the average ascii values for lst[j] and lst[j+1].
Reply
#3
Hi, first of all, thanks for the reply.
Secondly:
" you add up the ordinal value for each letter and divide by the number of letters" - didn't really understand, sorry.
ordinal? no idea what it is.
you mean, as I said, make a function that takes a string and divides it to a single characters and then find the ascii value ( with ord ) right?

About word, look the entire code, word is the list. ( look at the other functions and then you will understand )

About: "much like the key parameter for sort. This would not only result in less and simpler code, but it would fix your problem."
How exactly? I thought of something like that, but I couldn't think of anything. Also, I've been asked in the question to think which function write for each one ( I think it means I need to separate ).

About: # This comparison is not valid. It does not compare the average ascii value
Yea I know its not valid lol, I just tried a few stuff, that was the closest I could do and its not working properly sadly...

About: You need to create a function or a loop that computes the average ascii value of a word (I would write a function).
Yea, I know, I tried it, was unsuccesfull sadly... I will try it again although, I guess its the only way to do it...

About: You will use this code to compute average ascii values for lst[j] and lst[j+1], compare the result and swap when indicated.
Yea, sadly, the first function is the problematic, I'll try it again though.

About: parameter word
Look at the code above.
Reply
#4
The reason I got in trouble is because of this:
I tried to code it with a list done already ( in a new window.py ), so it will be more comfortable to try it.
word = ["hello", "my", "dear", "properly"]

def seperated_words(lst):
    words = "".join(word)
    for i in words:
        print(ord(i))
    print(words)

seperated_words(word)
I can get the ascii value, the only problem is how do I seperate it... If I knew how to seperate it, I could finish the question and thus not opening this thread hehe, but that is the problem, which I wanted to open the thread.
output:
104
101
108
108
111
109
121
100
101
97
114
112
114
111
112
101
114
108
121
hellomydearproperly
Reply
#5
Surprised you don't understand ordinal since ord() is a function that returns the ordinal value of a unicode character.

From your example it appears you are using ord() to get the average ascii value. ord() returns an integer. How would you compute the average of a list of integers?

Why are you using "word" when you pass "word" as an argument to sorting_by_ascii_average(lst). You should be using "lst". I know they are the same, but it is poor programming to pass an argument to a function and not use it. All your sort functions should take an argument which is the list to sort, and they should refer to that list using the function argument name. Use of global values should be kept to a minimum and global variables should not be used as a way to pass parameters to a function..

How do you provide a key function to sort? There are lots of examples. Are you wondering how you would call the function?
def bubble_sort(items, key):
    items = items.copy()  # Do not alter origional items list
    for i in range(len(items)-1, -1, -1):
        for j in range(i):
            if key(items[j]) > key(items[j+1]):
                items[j], items[j+1] = items[j+1], items[j]
    return items

words = input('Enter words: ').split()

print('Words:', words)
print('Sorted by length:', bubble_sort(words, key=len))
print('Sorted lexically (ignoring case):', bubble_sort(words, key=str.lower))
Output:
Words: ['Now', 'is', 'the', 'time', 'for', 'all', 'good', 'programmers', 'to', 'learn', 'Python'] Sorted by length: ['is', 'to', 'Now', 'the', 'for', 'all', 'time', 'good', 'learn', 'Python', 'programmers'] Sorted lexically (ignoring case): ['all', 'for', 'good', 'is', 'learn', 'Now', 'programmers', 'Python', 'the', 'time', 'to']
Reply
#6
Why are you joining the words?

You should start by writing a function that returns the average of a list of integers. Once that is working, modify the function to receive a string and generate a list of integers where each integer is the ordinal value of one of the letters in the string. Once you have the list of ordinal values it should be easy to compute the average.
Reply
#7
(Sep-07-2021, 08:19 PM)deanhystad Wrote: Surprised you don't understand ordinal since ord() is a function that returns the ordinal value of a unicode character.

From your example it appears you are using ord() to get the average ascii value. ord() returns an integer. How would you compute the average of a list of integers?

Why are you using "word" when you pass "word" as an argument to sorting_by_ascii_average(lst). You should be using "lst". I know they are the same, but it is poor programming to pass an argument to a function and not use it. All your sort functions should take an argument which is the list to sort, and they should refer to that list using the function argument name. Use of global values should be kept to a minimum and global variables should not be used as a way to pass parameters to a function..

How do you provide a key function to sort? There are lots of examples. Are you wondering how you would call the function?
ef bubble_sort(items, key):
    items = items.copy()  # Do not alter origional items list
    for i in range(len(items)-1, -1, -1):
        for j in range(i):
            if key(items[j]) > key(items[j+1]):
                items[j], items[j+1] = items[j+1], items[j]
    return items

words = input('Enter words: ').split()

print('Words:', words)
print('Sorted by length:', bubble_sort(words, key=len))
print('Sorted lexically (ignoring case):', bubble_sort(words, key=str.lower))
Output:
Words: ['Now', 'is', 'the', 'time', 'for', 'all', 'good', 'programmers', 'to', 'learn', 'Python'] Sorted by length: ['is', 'to', 'Now', 'the', 'for', 'all', 'time', 'good', 'learn', 'Python', 'programmers'] Sorted lexically (ignoring case): ['all', 'for', 'good', 'is', 'learn', 'Now', 'programmers', 'Python', 'the', 'time', 'to']

Oh about ordinal, I didnt know its the whole word for ord ( first time for me, I just knew that ord gets ascii ).

About : From your example it appears you are using ord() to get the average ascii value. ord() returns an integer. How would you compute the average of a list of integers?

answer: I know how to find the average of the whole list, but the problem is, I need to sort my list with strings based on ascii average.
I mean, if a list contains: ["hey", "hello"], I need to find the ascii of h,e,y in separate and ascii of h,e,l,l,o in separate and then sum the h,e,y and the other one, and then divide by the number of letter in the string.
But that is my problem, I cant manage to separate the strings in the list for it... I can only find the ord in the all letter in list, like that: h,e,y,h,e,l,l,o - without separating ( like the comment I did above ).

About: Word - yea I know, it kind of poor programing, I did it by accident at the beginning and forgot to change it. Ill change it now.

About: words = input('Enter words: ').split() ( in code )
didnt understand it, what it does? I didnt learn the split function, saw it before, tried to learn it, couldn't understand a thing... what is the point of the words =?

Ill try to change my function now so it will do like yours, thanks :) was really good idea, although its really out of my league to do something like that.. to think of something like that, its like top programming... using the key function, thinking of it and such... ( I am a complete beginner ).

About: the second comment:
No idea... How does the average of int in list will help me? I dont know ("modify the function to receive a string and generate a list of integers where each integer is the ordinal value of one of the letters in the string)...
Is it possible to do it as a beginner? seriously asking...
forgot to mention, but also the question said that once I write stop at the list, It will stop writing strings and not add the stop ( wrote it at the question, you probably missed it, but it doenst matter, with the words, I will just stick to the function I did ).
But ill be happy to get answers to the other questions I wrote.

EDIT:
There is something I just found online by searching the key function.
The key itself is some sort of sorting system, its not allowed to me.
I need to sort without using sort, sorted, reverse or any other system like that, only by using some sort functions - like bubble or selection like I did.
If a key is not a sort system, I will be happy to use it ( I will be happy if you can clarify that to me ).


Thanks.
I changed the code to be a little more understandable:

def words_to_list():
    growing_list = []  # Creating an empty list.
    while True:  # Continue till string: "stop".
        enter_word = input("Please enter your word: ")
        growing_list.append(enter_word)  # Adding the words to the list in each iteration.
        if enter_word == "stop":
            growing_list.remove("stop")
            break  # Finish function.
    return growing_list


words = words_to_list()
print(f"List not sorted: {words}")


def lexicography_list(lst):
    for i in range(len(lst) -1, -1, -1):
        for j in range(i):
            if lst[j] > lst[j + 1]:
                lst[j], lst[j + 1] = lst[j + 1], lst[j]
    return lst


lex_list = lexicography_list(words)
print(f"List sorted by alphabet: {lex_list}")


def sorting_by_length(lst):
    for i in range(len(lst) - 1, -1, -1):
        for j in range(i):
            if len(lst[j]) > len(lst[j + 1]):
                lst[j], lst[j + 1] = lst[j + 1], lst[j]
    return lst


length_list = sorting_by_length(words)
print(f"List sorted by length: {length_list}")
EDIT:
Just saw something about the ascii thingy: https://stackoverflow.com/questions/1806...-in-python
I saw there chr, no idea what it is, but it seems like it converts the ascii back to strings, I will try it maybe... see If I can work it out...

______________________________________________________________________________________________________________________________________________________________________________
LAST EDIT:

I tried something as you said above.
1. Getting the strings on the list.
2. Turning them to intergers ( by ord )
3. Having a list full of numbers ( which are int of string )
4. Summing all the numbers
5. Doing average
That's it.
The only problem is that, as I said, I dont know how to separate the strings / intergers from other intergers / string in the list.
I did that code: ( dont mind the variable names here, or the 2 definitions, and the long code. I can fix it later on, its on a new pywindow, just for trying it out ).
words = ["hello", "my", "dear", "properly"]

def list_of_letter_ascii_values(lst):
    word = ", ".join(words)
    listed = []
    for i in word:
        listed.append(ord(i))
    return listed

x = list_of_letter_ascii_values(words)
print(x)

def average_ascii_values(lst):
    total = 0
    for i in x:
        total += i
    average = total / len(x)
    return total, average

y, z = average_ascii_values(x)
print(y, z)
The problem with this code, it returns the average of all the int in the lists, If I knew how to separate, it was good ( the reason I used join before, but it also didnt help )
Reply
#8
I think the computer is making you stupid. This is a common problem with new programmers. Sitting at the computer makes you think too much about the coding aspect of programming and you forget to do the problem solving part. Of the two, problem solving is the important part of programming. You can know all the Python there is to know and you still can't write a program until you develop an algorithm to solve the problem.

When I get stuck I step away from the computer and think about the problem, not the program. This is an easy problem and you will see this if you grab pencil and paper and solve it by hand. Don't worry about the actual ordinal values. Don't even worry about case. Pick some short words and compute their average ordinal value using ord('a') == 1 and ord('z') == 26. Here are some words you can try along with their average ordinal value.

step = 15, away = 12.5, from = 13, the = 11, computer = 13.875

Once you have a process for computing the value, write down the steps used to accomplish the task. This is your algorithm. Now all you have to do is translate it to Python. Are there any steps you have to repeat? That is a good place for a loop. Do you have to write something down or remember something? That indicates you will need a variable. Here's a start for your function. The function should use the argument "word" and not some global variable
def avg_ord_value(word):
    '''Return average ordinal value for the letters in word'''
    # Your code goes here
When the code is working you can test with some words. These are the average ordinal when using the ord() function instead.

step = 111, away = 108.5, from = 109, the = 107, computer = 109.875

Notice they are all offset by 96. The difference between ord('a') in our made up character set ('a' == 1) and the utf-8 character set that Python uses by default ('a' = 97)
Please use new posts to add information to the conversation. I don't know where your edits fit in the conversation timeline.

A sorting key is not a sort. A sorting key is a user provided function to compute a proxie (stand-in) value that is used when comparing the items to sort. In this example a sorting key is used to sort number strings by their numeric value.
values = ['5', '33', '1', '22', '9', '6.7']

def bubble_sort(items, key=lambda x:x):
    items = items.copy()  # Do not alter origional items list
    for i in range(len(items)-1, -1, -1):
        for j in range(i):
            if key(items[j]) > key(items[j+1]):
                items[j], items[j+1] = items[j+1], items[j]
    return items

print('String sort:', bubble_sort(values))
print('Numerical sort:', bubble_sort(values, float))
Output:
String sort: ['1', '22', '33', '5', '6.7', '9'] Numerical sort: ['1', '5', '6.7', '9', '22', '33']
The string sort compares the values without conversion. "lambda x: x" is a way to write a function that returns the value of it's argument. A shorthand for this:
def return_argument(arg):
    return arg
When treating the values as strings, '33' is less than '5' because '3' is less than '5'.

When sorting the values by their numerical value the key converts each str to a float number, and the sort uses the float number when comparing items. The sort is still sorting the original strings, but when it compares '33' to '5' it first converts the str '33' to the float number 33.0 and the str '5' to the float number 5.0, then it compares:
if 33.0 > 5.0:
    items[j], items[j+1] = items[j+1], items[j]
Average ordinal value of 'step':
ord('s') = 115
ord('t') = 116
ord('e') = 101
ord('p') = 112
sum = 444
average = 444 / 4 = 111
ben1122 likes this post
Reply
#9
I will try, thanks :(
Reply


Possibly Related Threads…
Thread Author Replies Views Last Post
  Sorting a copied list is also sorting the original list ? SN_YAZER 3 3,047 Apr-11-2019, 05:10 PM
Last Post: SN_YAZER

Forum Jump:

User Panel Messages

Announcements
Announcement #1 8/1/2020
Announcement #2 8/2/2020
Announcement #3 8/6/2020