Place value + value of letters


8 posts
by zomzilla » Sun Dec 16, 2012 9:24 pm
Hi all,

I have written a simple program which sorts a list of numbers and/or letters.

BUT!

number 233 for example, will come before 3, due to the leading 2.
A similar thing happens with words.

I have used a simple
number1 > number2
line to see which of a pair is bigger.

My question is: how may I add place value to my program?

thanks
Posts: 42
Joined: Wed Nov 16, 2011 3:04 pm
by davef21370 » Sun Dec 16, 2012 9:45 pm
Post the code, let's have a look.
Please feel free to tap into my abundant lack of knowledge.
User avatar
Posts: 426
Joined: Fri Sep 21, 2012 4:13 pm
Location: Up North
by -rst- » Mon Dec 17, 2012 3:48 pm
As you say 'similar thing happen with words' you are at the essence of the issue: your variables are most likely strings/text, so even though what you think of as numbers are actually string/text representation of the number - and because strings/text is sorted alphabetically (not numerically), "223" comes before "3".

Code: Select all
Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32
Type "help", "copyright", "credits" or "license" for more information.
>>> print 2 < 3
True
>>> print 223 < 3
False
>>> print "223" < "3"
True
>>> print "a2" < "a3"
True
>>> i = 223
>>> j = 3
>>> print i < j
False
>>> i = "223"
>>> j = "3"
>>> print i < j
True
>>>


Now, as you say 'program which sorts a list of numbers and/or letters' you cannot really get both:
- if you have only numbers (in numeric variables), you can sort them in numeric order
- if you have only letters, you can sort then in alphabetic order
- if you have mixed numbers and letters, you can sort them in alphabetic order (or you have to create your own comparison function that returns something else)

Hope that is clears it at least a bit!

Hmm... just out of curiosity tried this:

Code: Select all
>>> print "a" < 65
False
>>> print "2" < 3
False

...so it seems you can compare numbers and strings, but how the Python compares them is beyond me (a beginner in Python myself).
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 895
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by rurwin » Mon Dec 17, 2012 4:22 pm
@ -rst-, it looks like it is comparing the ASCII (or maybe Unicode) encoding of the character. "2" is 50, and "a" is 97.

The problem is that things can get complex and ambiguous. How should these strings be ordered?

this2string1000
this19string900
1,456,234.3
1.456.234,3
1456234.3
14562343

It is ambiguous enough that any general solution would be insufficient more often than it was useful.

The pragmatic solution is to always use the same number of digits with leading zeros.
User avatar
Forum Moderator
Forum Moderator
Posts: 2890
Joined: Mon Jan 09, 2012 3:16 pm
by zomzilla » Mon Dec 17, 2012 4:47 pm
Ok so having read your post I abandoned the idea of supporting non-number inputs.

To fix my code I changed the raw_input() to input() (code below) which seems to have changed the variable type in my list.

here is my (messy) code:
Code: Select all
list_in=[]
iterations = 1
inputs=0

print "how many numbers do you want to input?\n"
to_be_input=input()
print "input integers plz; and 00 to end input\n"
while inputs<to_be_input:
   input_last = input()
   input_last
   list_in.append(input_last)
   inputs=inputs+1
print "you just input\n" ,list_in, "\n beginning sorting"

#next bit iterate until there is no more change between iterations

while 1<2:
   Y=1
   changes=0
   while Y<len(list_in):  #this loop is the single do/dont flip part of the code
   
      X=Y-1
      if list_in[X] > list_in[Y]:
         tempX=list_in[X]
         tempY=list_in[Y]
         list_in[X]=tempY
         list_in[Y]=tempX
         changes=1
      Y=Y+1
   print iterations,list_in
   iterations=iterations+1

   if changes==0:
      break
print list_in


now changing the raw_input() to input() means I cant have my nice input loop :(

1st: is there a way I can change the data type from raw_input to the type input() gives?
2nd: feel free to scream at me about how poor my code is: i want tips on how to improve it

thanks guys

PS: I know bubble sort is not the most efficient, but that is not the point of this
Posts: 42
Joined: Wed Nov 16, 2011 3:04 pm
by -rst- » Mon Dec 17, 2012 5:46 pm
Bubble sort is one of the best algorithms to start with (simple enough to understand and simulate with pen and paper)!

What do you think is 'not so nice' with this input loop?

I assume the 'and 00 to end' is left from your original... There is one extra line within the loop: the lonely 'input_last'. Other that that it looks ok - maybe the variable names could be a bit more descriptive and at least follow the same pattern: to_be_input, last_input, input_list, n_inputs (or num_inputs) ...these are a bit of a question of personal taste as well...

In the bubble sort you should be able to do the swap with only one extra variable - or maybe even without any - this is a good exercise ;) The while loop as it is now, the test '1<2' could(/should) be written as 'True' (just because Python offers the boolean variable type, that is missing from many languages). Also the changes variable could be a boolean... And to polish it off, use a real (boolean) variable to replace the 'while True' + 'break'.

Guess that covers the Question 2 :D

Answer to question 1: you could do
Code: Select all
last_input = int(raw_input())

...which is better than input() as it would fail for anything not integer ...obviously a good programmer would make sure the code can gracefully handle this - after you get all the rest working, see handling exceptions ;)

Something to think... :)
http://raspberrycompote.blogspot.com/ - Low-level graphics and 'Coding Gold Dust'
Posts: 895
Joined: Thu Nov 01, 2012 12:12 pm
Location: Dublin, Ireland
by zomzilla » Mon Dec 17, 2012 5:55 pm
Thanks a lot!

yes the input 00 was an experiment to see if I could end the loop like that (before, I had it break on an empty space)

I see what you mean about the switch too: but I was going for ease-of-thinking rather than efficiency.

now to tinker on quick sort.... ( a bit more challenging methinks)
Posts: 42
Joined: Wed Nov 16, 2011 3:04 pm
by rurwin » Mon Dec 17, 2012 6:55 pm
"input()" is a security hole. The user can type Python code in and it will get interpreted

Code: Select all
x = 42
y = input()
print y

if the user types "x" then y is set to 42. Try it.

For that reason input() in Python 3 is redefined to be the same as raw_input() in Python 2, and Python 2 users are encouraged to use raw_input() only.

raw_input() always returns a string and it is the program's responsibility to convert it. Unfortunately the only clean way to do that is to use exceptions.
Code: Select all
   x = raw_input()
   try:
      input_last = int(x)
   except ValueError:
      try:
         input_last = float(x)
      except ValueError:
         input_last = x

We try to convert it to an integer first, because that's the most stringent. If that fails we try to convert it to a float, and if that fails we leave it as a string.

Now we need to be able to compare strings with numbers, so we define a function to do that. It takes two parameters: a and b, and it returns -1 if a<b, +1 if a>b and 0 if they are the same:
Code: Select all
def mytest (a, b):
   if type(a) == str and type(b) != str:
      return -1
   elif type(a) != str and type(b) == str:
      return +1      
   elif a < b:
      return -1
   elif a > b:
      return +1
   else:
      return 0

that just orders all strings lower than all numbers, but you can obviously enhance it if you have a better ordering in your application.

And you use the comparison function in the sort function:
Code: Select all
while True:
   Y=1
   changes=0
   while Y<len(list_in):  #this loop is the single do/dont flip part of the code
   
      X=Y-1
      if mytest(list_in[X], list_in[Y]) > 0:
         tempX=list_in[X]
         tempY=list_in[Y]
         list_in[X]=tempY
         list_in[Y]=tempX
         changes=1
      Y=Y+1
   print iterations,list_in
   iterations=iterations+1

   if changes==0:
      break
print list_in

By the way, you could just use
Code: Select all
list_out = sorted(list_in)

It does actually work, but the way it sorts strings and numbers is not defined and may change. So to be correct you have to tell it your comparison function. You can do that in Python 2:
Code: Select all
list_out = sorted(list_in, cmp=mytest)

but in Python 3 they've taken out the cmp parameter and the equivalent method requires even more newbie unfriendly language features.
User avatar
Forum Moderator
Forum Moderator
Posts: 2890
Joined: Mon Jan 09, 2012 3:16 pm