0

I have a txt file with 2 column, first column is the car name, second column is gallon used per hour, I'm trying to sort it in descending order with the second column value with code below:

import operator
car = open('Mileage.txt', 'r')
car_content = car.read()
sorted_content = sorted(car_content, key = operator.itemgetter(1), reverse=True)
print(car_content)
car.close()

I receive an error 'sorted_content = sorted(car_content, key = operator.itemgetter(1), reverse=True)

IndexError: string index out of range'

If I change the

key = operator.itemgetter(0)

It works but only prints the file without descending it.

file link: https://drive.google.com/file/d/1HW7zhGKVTHYLs4SrdQ1XMrc3k01BA3nT/view?usp=sharing

How can I fix it?

evenevaa
  • 25
  • 5
  • 3
    provide the file as well – Neeraj Apr 13 '21 at 07:35
  • 1
    When you do `car_content = car.read()`, what exactly are you expecting `car_content` to end up as? It seems like you're expecting a list of lists, where each of the sublists has two items corresponding to the "columns" in a line of the file. But... how is that supposed to work? `.read()` is not magic. – Karl Knechtel Apr 13 '21 at 07:40
  • Also: pycharm is your editor; it has **no effect** on how the code operates and is **only** a tool that you use to help write the code. I removed that tag and info from your question because they are not relevant; you should bring this up for questions about how to use the program itself (e.g. how to tell it which version of Python to use, how to indent code quickly etc etc.) – Karl Knechtel Apr 13 '21 at 07:42
  • "but only prints the file without descending it." I don't understand what this is supposed to mean. What do you think it means to "descend" a file? – Karl Knechtel Apr 13 '21 at 07:42
  • 2
    Does this answer your question? [sort csv by column](https://stackoverflow.com/questions/2100353/sort-csv-by-column) – Tomerikoo Apr 13 '21 at 07:48
  • @KarlKnechtel I meant i want to display the rows in descending order – evenevaa Apr 13 '21 at 08:17

2 Answers2

0

Let's review how the operator.itemgetter() works - Say you have got a list of tuple like this -

list1 = [(1,2,3),
        (4,5,6)]

If I select operator.itemgetter(0). That means I want the 1st value from the tuple. This function can be mapped to a list via -

#map
print(list(map(operator.itemgetter(0), list1))) #
#list comprehension
print([operator.itemgetter(1)(val) for val in list1])

The 1st one will print - # [1,4] The 2nd one will print - # [2,5]

Some suggestion on file reading -

Use context manager to open the file. It'll automatically close the file after reading. The lines from the file will contain the '\n'(A newline character). That you may wanna strip off.

with open('Mileage.txt', 'r') as car:
    car_content = car.read().splitlines() 

When you read the file content like this. List car_content will contain the list of strings -

['Prius,2.1', 'Camry,4.1', 'Sebring,4.2', 'Mustang,5.3 ', 'Accord,4.1', 'Camry,3.8', 'Camry,3.9', 'Mustang,5.2', 'Accord,4.3', 'Prius,2.3', 'Camry,4.2', 'Accord,4.4']

operator.itemgetter(1) will not work on the above list as every item in the list contains 1 single string separated via ',' and that's why you're getting the error list index out of range.

Now, what you need to do is to split this list on ',' -

car_content = [tuple(car.split(',')) for car in car_content]

This will give you the list of tuples -

[('Prius', '2.1'),
('Camry', '4.1'),
('Sebring', '4.2'),
('Mustang', '5.3 '),
('Accord', '4.1'),
('Camry', '3.8'),
('Camry', '3.9'),
('Mustang', '5.2'),
('Accord', '4.3'),
('Prius', '2.3'),
('Camry', '4.2'),
('Accord', '4.4')]

You can use the sorted function now with either 0 or 1. Here's the complete code-

import operator
with open('test.txt', 'r') as car:
    car_content = car.read().splitlines()  
car_content = [tuple(car.split(',')) for car in car_content]
sorted_content = sorted(car_content, key = operator.itemgetter(1), reverse=True)
print(sorted_content)

With output -

[('Mustang', '5.3 '),
('Mustang', '5.2'),
('Accord', '4.4'),
('Accord', '4.3'),
('Sebring', '4.2'),
('Camry', '4.2'),
('Camry', '4.1'),
('Accord', '4.1'),
('Camry', '3.9'),
('Camry', '3.8'),
('Prius', '2.3'),
('Prius', '2.1')]
Nk03
  • 14,699
  • 2
  • 8
  • 22
  • Hi thanks for the explanation but the file is like this: https://drive.google.com/file/d/1HW7zhGKVTHYLs4SrdQ1XMrc3k01BA3nT/view?usp=sharing – evenevaa Apr 13 '21 at 08:25
  • The problem isn't with OP's understanding of `itemgetter`; the problem is with OP's understanding of how to read and parse the file contents. – Karl Knechtel Apr 13 '21 at 08:25
  • I just want to sort the lines decendingly by the second column value, which I think is the key = ... in my code? but I def made some mistake – evenevaa Apr 13 '21 at 08:26
  • The problem is that the data that you read in doesn't have "lines", and doesn't have "column values", because you did not do any work to *interpret the contents*. It's all just one string. – Karl Knechtel Apr 13 '21 at 08:28
  • I've made changes to my ans @evenevaa – Nk03 Apr 13 '21 at 08:42
  • @Nk03 oh i get it now! thanks! you are wonderful – evenevaa Apr 13 '21 at 08:45
0

You first need to format your data in lines and columns, here you are just reading the file as one string. Your file data structure is CSV (Comma Separated Values), you should read it line by line and then split each line at comma:

with open("Mileage.txt.txt", "r") as f:
  data = f.readlines()

data = [line.strip().split(",") for line in data]
data = [(line[0], float(line[1])) for line in data]

You can then sort the list of tuples:

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

I recommend you to read the doc for strip, split, open and readlines as well as printing the data between each operation to understand the process.

Louis Lac
  • 5,298
  • 1
  • 21
  • 36