0

I have a txt file that looks like this:

Raj,Joy:9,8,1

Smith,John:8

Campbell,Michelle:5,7,9

NOTE: There is no empty lines between the lines of text in the text file

I want to output each result of each person in descending numerical order, e.g.

Campbell,Michelle:9

Raj,Joy:9

Raj,Joy:8

Smith,John:8

Campbell,Michelle:7

etc.

The code I have so far is this:

            data = src.readlines()
            for line in data:
                record = line.split(':')
                scoreList = record[1].split(',')
                # Add name to fileRecord
                for n in scoreList:
                    fileRecord.append(record[0])

                # Two dimensional list created, each item is one set of scores
                fileScores.append(scoreList)

where src is the text file. The main problem posed for me is if I invoke .sort() on sortList I lose the order and so cannot match each score with its corresponding name. If I were to create a dictionary the problem posed is outputting the sorted data individually as sorting

{"Raj,Joy":[9,8,1],etc}

would not sort it by each individual score that "Raj,Joy" got, but I cant split the list because then I would have duplicate keys.

joyalrj22
  • 115
  • 4
  • 12

5 Answers5

2

You already have filled fileRecord and fileScores. Now you combine them and sort:

>>> fileRecord = ['Raj,Joy', 'Smith,John', 'Campbell,Michelle']

>>> fileScores = [[9, 8, 1], [8], [5, 7, 9]]

>>> comb = []

>>> for record, scores in zip(fileRecord, fileScores):
...     for score in scores:
...         comb.append((record, score))
...         

>>> comb
>>> 
[('Raj,Joy', 9),
 ('Raj,Joy', 8),
 ('Raj,Joy', 1),
 ('Smith,John', 8),
 ('Campbell,Michelle', 5),
 ('Campbell,Michelle', 7),
 ('Campbell,Michelle', 9)]

>>> comb.sort(key=lambda item: item[1], reverse=True)

>>> comb
>>> 
[('Raj,Joy', 9),
 ('Campbell,Michelle', 9),
 ('Raj,Joy', 8),
 ('Smith,John', 8),
 ('Campbell,Michelle', 7),
 ('Campbell,Michelle', 5),
 ('Raj,Joy', 1)]

You would want to use itertools.izip instead of the built-in zip in Python 2.

warvariuc
  • 57,116
  • 41
  • 173
  • 227
2

Open the file and str.rpartition each line to isolate the numbers from the name. Then build a generator to expand name with each of its numbers, sort that, then do whatever you need for outputting, eg:

Code:

with open('input_file') as fin:
    name_nums = (line.rpartition(':')[::2] for line in fin)
    expanded = ((name, int(n)) for name, num in name_nums for n in num.split(','))
    ordered = sorted(expanded, key=lambda L: L[1], reverse=True)
    for name, num in ordered:
        print '{}:{}'.format(name, num)

Output:

Raj,Joy:9
Campbell,Michelle:9
Raj,Joy:8
Smith,John:8
Campbell,Michelle:7
Campbell,Michelle:5
Raj,Joy:1
Jon Clements
  • 138,671
  • 33
  • 247
  • 280
0

You can use sorted function with a desire key :

>>> s="""Raj,Joy:9,8,1
... 
... Smith,John:8
... 
... Campbell,Michelle:5,7,9"""

>>> l=s.split('\n\n')
>>> from itertools import chain    
>>> for i in sorted(chain(*[[(i[0],j) for j in i[1].split(',')] for i in [i.split(':') for i in l]]),key=lambda x: x[1],reverse=True) :
...   print ':'.join(i)
... 
Raj,Joy:9
Campbell,Michelle:9
Raj,Joy:8
Smith,John:8
Campbell,Michelle:7
Campbell,Michelle:5
Raj,Joy:1

So all we have down in above one line code if as below :

first we split the text with tow new line ('\n\n') and put it in l :

l=s.split('\n\n') 
>>> l
['Raj,Joy:9,8,1', 'Smith,John:8', 'Campbell,Michelle:5,7,9']

then you need to create a list of pairs contain the names and scores :

>>> [[(i[0],j) for j in i[1].split(',')] for i in [i.split(':') for i in l]]
[[('Raj,Joy', '9'), ('Raj,Joy', '8'), ('Raj,Joy', '1')], [('Smith,John', '8')], [('Campbell,Michelle', '5'), ('Campbell,Michelle', '7'), ('Campbell,Michelle', '9')]]

and at last you need to first chain the nested lists and then sort this list based on second element (score) with sorted function and the following key :

key=lambda x: x[1]

and if you want to write to file :

with open ('sample_file','w') as f :
     for i in sorted(chain(*[[(i[0],j) for j in i[1].split(',')] for i in [i.split(':') for i in l]]),key=lambda x: x[1],reverse=True) :
        f.write(':'.join(i))
Mazdak
  • 105,000
  • 18
  • 159
  • 188
0
s = """Raj,Joy:9,8,1
Smith,John:8
Campbell,Michelle:5,7,9"""

Use getKey to provide tuples second element as key to sorted()

def getKey(item):
    return item[1]

Declare your list objects

asc_list = []
result = []

Use list comprehension to split input into separate lines:

asc_list = [i for i in s.split("\n")]
asc_list = [(j.split(':')[0],k) for j in asc_list for k in j.split(':')[1].split(',')]

Use sorted to sort on tuple item number 2

result =  sorted(asc_list_nums, key=getKey)

Output:

[('Raj,Joy', '1'), ('Campbell,Michelle', '5'), ('Campbell,Michelle', '7'), ('Raj,Joy', '8'), ('Smith,John', '8'), ('Raj,Joy', '9'), ('Campbell,Michelle', '9')]
nitimalh
  • 919
  • 10
  • 26
0

Perfect example for a Python one-liner. Applying list comprehensions and built-in sorted function.

Flattening the combined lists into a list of tuples

scores = [(record, score) for record, scores in zip(fileRecord, fileScores) for score in scores]

Sort list of tuples by score in descending order

from operator import itemgetter
sorted(scores, key=itemgetter(1), reverse=True)

Problem solved in a single line

sorted([(record, score) for record, scores in zip(fileRecord, fileScores) for score in scores], key=itemgetter(1), reverse=True)

Useful References

Glorfindel
  • 21,988
  • 13
  • 81
  • 109
Sascha Gottfried
  • 3,303
  • 20
  • 30