How do I alphabetically sort every -n line in a text file, and have the remaining information follow along?

Question:

I am trying to sort a text file in alphabetical order (names) but I still want the information regarding the specific persons to follow with the reordering. I know it sounds weird, but an example might help.

Every person has two names, a phone number, en email address, and an address. When I sort the file, I want the information about every specific person to follow with them.

Text file:

Bob Steven
02847661723
[email protected]
Bob Street 121
Alex Ericsson
1233213211
[email protected]
Alex Street 112
Chris Philips
018207129387
[email protected]
Christ Street 902

When sorted, it should be something like this:

Alex Ericsson
1233213211
[email protected]
Alex Street 112
Bob Steven
02847661723
[email protected]
Bob Street 121
Chris Philips
018207129387
[email protected]
Christ Street 902

I found this string of code which kind of works, but it sorts every single line. How do I make it so it only sorts every 4th line (1st line, 5th line and so on)?

input_filename = "filename.txt"
output_filename = "filename.txt"

with open(input_filename, "r") as f:
    l = [line for line in f if line.strip()]

l.sort(key=lambda line: line.split())

with open(output_filename, "w") as f:
    for line in l:
        f.write(line)
Asked By: Voltz

||

Answers:

You can try:

with open("input.txt", "r") as f_in:
    data = [line for line in map(str.strip, f_in) if line]

data = sorted(
    [data[i : i + 4] for i in range(0, len(data), 4)], key=lambda k: k[0]
)

with open("output.txt", "w") as f_out:
    for chunk in data:
        print(*chunk, file=f_out, sep="n")

This creates output.txt with contents:

Alex Ericsson
1233213211
[email protected]
Alex Street 112
Bob Steven
02847661723
[email protected]
Bob Street 121
Chris Philips
018207129387
[email protected]
Christ Street 902
Answered By: Andrej Kesely
s = """Bob Steven
02847661723
[email protected]
Bob Street 121
Alex Ericsson
1233213211
[email protected]
Alex Street 112
Chris Philips
018207129387
[email protected]
Christ Street 90"""


data = 'n'.join(['n'.join(x) for x in sorted([s.split('n')[i:i+4] for i in range(0, len(s.split('n')), 4)], key=lambda x: x[0])])
print(data)

output:

Alex Ericsson
1233213211
[email protected]
Alex Street 112
Bob Steven
02847661723
[email protected]
Bob Street 121
Chris Philips
018207129387
[email protected]
Christ Street 90
Answered By: 555Russich

Basically, what want to do here is read your file in chunks, and then sort each chunk. Andrej has already demonstrated how to do that, but let’s take it up a notch. Let’s define a class to encapsulate the data for each person. The class contains attributes name, phone, email, address to store each of our data fields, and methods __str__ to convert the class back to a string (to print to screen/file), and __eq__ and __gt__ to define comparison to other objects of the class (to sort). We can also define a class method from_iter that will take in a file handle (or other iterator) and consume its first four elements to define a Person object:

def Person:
    def __init__(self, name, phone, email, address):
        self.name = name
        self.phone = phone
        self.email = email
        self.address = address

    @classmethod
    def from_iter(cls, src):
        return Person(next(src), next(src), next(src), next(src))

    def _as_tuple(self):
        return (self.name, self.phone, self.email, self.address)

    def __repr__(self):
        return f"Person({repr(self.name)}, {repr(self.phone)}, {repr(self.email)}, {repr(self.address)})"

    def __str__(self):
        return "n".join(self._as_tuple())

    def __eq__(self, other):
        return self._as_tuple() == other._as_tuple()

    def __gt__(self, other):
        return self._as_tuple() > other._as_tuple()

Now, we can open the file and pass the handler to the reader function:

people = []
with open(input_filename) as f_in:
    try:
        people.append(Person.from_iter(f_in))
    except StopIteration: # Thrown when the file is exhausted
        pass

Now, we have the following people list:

[Person('Bob Steven', '02847661723', '[email protected]', 'Bob Street 121'),
 Person('Alex Ericsson', '1233213211', '[email protected]', 'Alex Street 112'),
 Person('Chris Philips', '018207129387', '[email protected]', 'Christ Street 902')]

Sorting this list is easy — use the sorted function, and since we already defined the __eq__ and __gt__ methods, the class can figure out how its objects compare to each other. In this case, the _as_tuple() of each object is compared, which simply compares the names first, then the phones, then the emails, and finally the addresses of the two objects. Simply doing sorted(people) gives

[Person('Alex Ericsson', '1233213211', '[email protected]', 'Alex Street 112'),
 Person('Bob Steven', '02847661723', '[email protected]', 'Bob Street 121'),
 Person('Chris Philips', '018207129387', '[email protected]', 'Christ Street 902')]

And to write it back to a file:

sorted_people = sorted(people)

with open(output_filename, "w") as f_out:
    for p in sorted_people:
        f_out.write(str(p)) # Use the __str__ defined in the class
        f_out.write("n") # Because a newline needs to be explicitly written

we get the desired output:

Alex Ericsson
1233213211
[email protected]
Alex Street 112
Bob Steven
02847661723
[email protected]
Bob Street 121
Chris Philips
018207129387
[email protected]
Christ Street 902
Answered By: Pranav Hosangadi
Categories: questions Tags: , , ,
Answers are sorted by their score. The answer accepted by the question owner as the best is marked with
at the top-right corner.