First time I've asked for help so please bear with me...
***Brain Freeze***
OK
Supposed to open a txt file. Assuming the txt file is formated properly. The file is a what I am assuming a list of names and ages. I created my own file...
kick me 989
bodybody 344
Santa Clause 0943
Bart Simpson 100
As Is 2856

Supposed to sort by the ages.
I will put the code i have in already.

def main():
infile = open('people.txt', 'r')
names = infile.readlines()
infile.close()

print names[0:1]
temp = names[0:1]
print temp
for item in temp:
item.split(' ')
print item
main()

Was trying to test this out but I kept messing up the indexing or listing.
Someone mentioned import string so Im going to try that.

I don't know how these boards work so Im crossing my fingers.
Also can someone show me how to encase my code ;)

Recommended Answers

All 14 Replies

OK figured this part out at least:
Enter the following into a people.txt file

kick me 989
bodybody 344
Santa Clause 0943
Bart Simpson 100
As Is 2856

def main():
     infile = open('people.txt', 'r')
     names = infile.readlines()
     infile.close()

     print names[0:1]
     temp = names[0:1]
     print temp
     for item in temp:
          item.split(' ')
     print item
main()

I think you've got a couple of challenges here. You have to deal with the fact that you're sorting on a field at the end of each line and you have to deal with the fact that some names have spaces and some do not. Thus the age could be in field 3 (most cases) but could also be in field two.

So first you want to open the file and read the lines into a variable. You've got that part down.

Next, I think you want to bring the last element of each line up to be the first element of each line. Here is something to get you started. Put this into a function and pass each item in your names list to the function. Catch the results in another list. Sort the list when you're done.

for entry in names:
  listofwords = entry.split(' ')

  # There is a newline character at the end that we want to get rid of
  listofwords[-1] = listofwords[-1].strip()

  # Take the last element and move it to the begining
  listofwords.insert(0, listofwords[-1])
  listofwords.pop()

  # Now take the list of words and turn it back into a single string
  returnstring = ''
  for word in listofwords:
    returnstring += word + ' '

  # Now there is a space at the end of our returnstring that we dont
  # want.  Remove it and return the string to main
  return returnstring.strip()

I would like to know if there is an easier way than what I just did.

Deleted last quick post.
Wasn't paying attention to the code. Ill keep working...

When you get to the actual sorting, you kinda need to compare numbers and not strings. When comparing strings, '1234' comes before '2', and that's just not right.

For the splitting of the name from the age, look at rsplit(' ', 1) that splits the string into an array of 2 strings on the last space in the line.

Then you can use int(agepart) to get the numeric value.

If you add the name and age to a list as tuples people.append((age,name)) (the double parens are on purpose) you can then use the default list sort() to order the list.

I would like to know if there is an easier way than what I just did

Would raise red flags for a beginning homework assignment like above, but you can use operator to sort on any list element

import operator

data = [
'kick me 989',                                              
'bodybody 344',
'Santa Clause 0943',
'Bart Simpson 100', 
'As Is 2856' ]

##  sort on last element
data_as_lists = [ rec.split() for rec in data ]   ## convert into list of lists
data_as_lists.sort(key=operator.itemgetter(-1))
print data_as_lists
print
for each_rec in data_as_lists :
   print each_rec

## or, using integers
for rec in data_as_lists:
   rec[-1] = int(rec[-1])
data_as_lists.sort(key=operator.itemgetter(-1))
print data_as_lists
print
for each_rec in data_as_lists :
   print each_rec

That is a much more elegant solution than mine...but you're right, it would probably raise some flags if you turned that in for your homework assignment. When I was taking C++ back in college the professor had a rule that you couldn't use anything that hadn't been covered in the text book yet.

Thanks... Im still working on it. Having trouble with the "FOR" statement. When I test it it only returns the last string in the list. 'As is 2856'. I did however pull the number out which is good a good thing for me since Im learning new stuff...
Thank you.

Don't know where I messed up but I was trying to return the function reading one line at a time. Was confused about the for loop...
When I used

print entry

after the for loop it just printed out the first or last string or item in the list. A little confusion here.
Here is the code I was using.

##people.txt

[LIST=1]
[*]def main():
[*]    infile = open('people.txt', 'r')
[*]    names = infile.readline()

[*]    
[*]    total = sorty(names,infile)
[*]    print total
[*]    
[*]    
[*]def sorty(names,infile):
[*]    while names:
[*]    
[*]        for index in names[:]:
[*]        
[*]               
[*]        
[*]            listofwords = index.rsplit(' ',1)
[*]        
[*]            listofwords[-1] = listofwords[-1].strip()
[*]        
[*]        

[*]            listofwords.insert(0, listofwords[-1])
[*]            listofwords.pop()
[*]        
[*]        
[*]            returnstring = ''
[*]            for word in listofwords:
[*]                returnstring += word + ' '
[*]            
[*]        return returnstring.strip()
[*]    names = infile.readline()
[*]    infile.close()
[*]    
[*]main()
[/LIST]

I am guessing the output I get is based on the spacing of some lines of codes.

The return you have inside sorty will return from the function and the code that is 'supposed to read more data' will never get run.

What happened to names = infile.readlines() that read all the lines at once, then you could just iterate over every line in the list. (If you would rather read the file one line at a time I understand, but the 'read it all at once' works REALLY well unless the file is huge.)

As far as only getting one return value, that is a function of how your list works.

** PS - to make your code look like the following, please use [code=python] #your code here

[/code] around your code.

for index in names[:]:
    listofwords = index.rsplit(' ', 1)
    listofwords[-1] = listofwords[-1].strip()
    listofwords.insert(0, listofwords[-1])
    listofwords.pop()
    returnstring = ''
    for word in listofwords:
        returnstring += word + ' '
return returnstring.strip()

The last return does not get called until after the for loop completes going through all of the names. Each time through the for loop, the return string is cleared (on line 6 in my post) and then rebuilt.

So if there were three names in the list, the returnstring gets built for each name, but it is discarded before we do anything with it. The only result available when we call return is the last entry.

Comment regarding line 1:
Do you know what the syntax names[:] means?
That is a slice reference that creates a copy of the whole names array. (In your case the list is relatively short so it should be ok, but you should be aware of what it is doing.) As you don't (in the code I see) try to modify index, you don't need to make a copy.

The call to rsplit() leaves index unchanged. The function split() works the same way.

a = "This is a test"
b = a.rsplit(" ")
print b
#['This', 'is', 'a', 'test']
print a
#This is a test

For the part of the code from line 6 to 9 where we put the list back together as a string (after we moved the last word to the front of the list) could more easily be done using join. It doesn't need the for loop and you don't need the final strip().

#continuing from above
b.insert(0, b[-1])
b.pop()
c = ' '.join(b)
print c
#test This is a
# there was no trailing space

If you want to have a function to 'clean up' a single line, you can do that without the while or the for loops. Just pass it a line and have it return the 'new' line with the last word as the first word in the new line.

def linefixup( line ):
    line = line.strip()
    # split the line into words.
    # if you're just going to put the string back together
    # anyway, the rsplit(' ', 1) doesn't make as much sense.
    words = split(' ')
    # add the last word as the first word
    words.insert(0, words[-1])
    # get rid of the last word we copied
    words.pop()
    # according to my interpreter, you could have used one line
    # for both of the above statements because pop() will return
    # what it is removing
    # words.insert(0, words.pop())
    return ' '.join(words)

Then in another piece of code that iterates over all of the lines from the file (or that processes the file one line at a time) you call the function and save the result in a list. Once you have processed all of the lines in the file, you can sort it and do something with the sorted list.

(The class operator.itemgetter is really cool too and I will be using it in the future, but you seemed to be avoiding it.)

This worked for me... removed the names = infile.readlines and opted for a loop. Hint on taking the numbers out would be helpful.
Im stuck on the printing out of "c". When I print it I get the first number of ever line.

def main():
    infile = open('people.txt', 'r')

    for line in infile:
        listofwords = line.split(' ',-1)
        listofwords[-1] = listofwords[-1].strip()
        listofwords.insert(0, listofwords[-1])
        returnstring =''
        listofwords.pop()
        c = ' '.join(listofwords)
        
main()

Alright, I tried making an empty list and then adding some results but the screen output keeps saying None.

I think maybe we have gotten 'off track'. The original problem was

Supposed to open a txt file. Assuming the txt file is formated properly. The file is a what I am assuming a list of names and ages. I created my own file...
kick me 989
bodybody 344
Santa Clause 0943
Bart Simpson 100
As Is 2856

Supposed to sort by the ages.

Most of the discussion (except for woooee's) has been about re-ordering the items on the line so you could use sort() (with the default parameters) to sort the list to meet your stated criteria.

What is the output supposed to be?

A list of the names in age order?

Bart Simpson
bodybody
Santa Clause
kick me
As Is

The same list with the ages included?

Bart Simpson 100
bodybody 344
Santa Clause 0943
kick me 989
As Is 2856

Would it be acceptable to list the ages first in the output?

100 Bart Simpson
344 bodybody
0943 Santa Clause
989 kick me
2856 As Is

For the outputs with ages, is it acceptable to output 943 in place of the 0943 we read for 'Santa Clause'?

We've read the file in with all lines at once and we've been working at reading one line at a time. Based on the stated goal, we will eventually need all of the data at once so we can order it. So one line a time is ok if that's what you want to do, but we will need all of the lines collected together before we can sort.

Here's some sample code that produces the third form of the output, but with 943 instead of 0943 for Santa Clause:

def main4():
    # the empty list we will sort
    tosort = []

    # open the file, process all the lines
    infile = open('people.txt', 'r')
    for line in infile:
        # get rid of the pesky last character
        tline = line.strip()
        # split the line into words
        twords = tline.split(' ')
        # get the integer value of the last word
        tnum = int(twords.pop())
        # put the name back together 
        # (only necessary if there was more than one word, but it will work anyway)
        tline = ' '.join(twords)
        # add a list with the integer and the name to the tosort list
        tosort.append([tnum, tline])
    # we've read all the data, close the file
    infile.close()

    # sort the list
    tosort.sort()

    # output the age and the name
    for data in tosort:
        print data[0], data[1]

main4()

Output from my run

100 Bart Simpson
344 bodybody
943 Santa Clause
989 kick me
2856 As Is

I don't think I used anything we haven't been talking about, but if you have any questions please ask. In the mean time if you wanted one of the other formats, please experiment with it...change a little, what does it do now? Change a little more, what about now?

It will help you to be more comfortable with the code and the way it works. (I think a form of iterative development is better for most problems. Its not quite test-driven as I don't write tests to see them fail before I add the new feature, but it does allow you to code and test in small pieces.)

Thanks for the sorting.
This is what I do not understand...

Please bear with me Im a little stressed for time and I probably started writing one hr from the posted time.
At the end of my code if I was to sort "c" or treat "c" as a list,
lets say I would put c = [0] then print c I would get the zero character of each line instead of a line zero.

The sorted output wouldn't matter but it would need to include the age and associated name.

Next question would be why do you have 4 after main?
Can you have more than one main? or is def main4 just another function apart from main?

Does .pop() alwasy take the last index?
Every time I try to pop() or do anything with a list I usually get the last digit instead of the full thing. I guess you cleared all that up though with the split But it doesn't work for me :(

I'm going to do some more reading and compare it with everyones code my 10 PHD instructor will know so I probably will do it in front of him after the break. Do not want to ask to many questions, I still have to put it inside a try and except and add two more functions.

Thanks for the help.

The reason it is main4() in my code is that this is the 4th version of the sort in the .py file main() was your version, main2() and main3() were versions of mine that did in another way. main4 is just a name, feel free to change it.

Python doesn't support a 'main'...the only reason your python file calls main is because you put main() at the bottom of the file without indenting it. So to run my code without losing yours, I wrote alternate versions of main (called main2, main3, main4) and called the one I was working on from where you called your main() .pop() always returns (and removes) the last thing on the list (unless you pass it an argument). If you were getting single letters, then the last thing on your list was single letters.

The following is the stream of input and output from an interactive python session: (started by just typing python)


This is what I saw when I typed what you posted:

>>> c=[0]
>>> print c
[0]
>>>

If c was a list, the c = [0] overwites the value.

Initialize a list and print the first item in the list:

>>> c =["Apple", "Banana", "Cherry"]
>>> print c
['Apple', 'Banana', 'Cherry']
>>> print c[0]
Apple

Iterating through the list to print it:

>>> for fruit in c:
...     print fruit
...
Apple
Banana
Cherry

Iterating through the list with indexes:

>>> for ii in range(len(c)):
...     print c[ii]
...
Apple
Banana
Cherry
>>>

Iterating through the list, printing a single character from each string in the list:

>>> for fruit in c:
...     print fruit[0]
...
A
B
C
>>>

If you're not quite sure how something works, at least skim the description on the manual page, but if you still have questions you can design a little test to see if something works the way you want. I like running these types of tests in interactive python because I can get immediate feedback.

Be a part of the DaniWeb community

We're a friendly, industry-focused community of developers, IT pros, digital marketers, and technology enthusiasts meeting, networking, learning, and sharing knowledge.