6

I have a text file includes over than 10 million lines. Lines like that:

37024469;196672001;255.0000000000
37024469;196665001;396.0000000000
37024469;196664001;396.0000000000
37024469;196399002;85.0000000000
37024469;160507001;264.0000000000
37024469;160506001;264.0000000000

As you seen, delimiter is ";". i would like to sort this text file by using python according to the second element. I couldnt use split function. Because it causes MemoryError. how can i manage it ?

11
  • 1
    Can you show the code you've tried? Commented Jan 22, 2013 at 18:06
  • So you say you can't load the file in memory? Commented Jan 22, 2013 at 18:10
  • That's only about 380MB of data. Are you running this on a phone? Commented Jan 22, 2013 at 18:10
  • @jordanm: double that when running on a 64-bit OS. 800MB for a 64-bit Python 3.3 build and the OP is letting Python decode the file data instead of treating it as binary. Commented Jan 22, 2013 at 18:16
  • 1
    @AndréLaszlo: The string (even as Unicode data) takes fewer bytes, actually. Python int and float types need a little more once converted. Commented Jan 22, 2013 at 18:19

3 Answers 3

22

Don't sort 10 million lines in memory. Split this up in batches instead:

  • Run 100 100k line sorts (using the file as an iterator, combined with islice() or similar to pick a batch). Write out to separate files elsewhere.

  • Merge the sorted files. Here is an merge generator that you can pass 100 open files and it'll yield lines in sorted order. Write to a new file line by line:

    import operator
    
    def mergeiter(*iterables, **kwargs):
        """Given a set of sorted iterables, yield the next value in merged order
    
        Takes an optional `key` callable to compare values by.
        """
        iterables = [iter(it) for it in iterables]
        iterables = {i: [next(it), i, it] for i, it in enumerate(iterables)}
        if 'key' not in kwargs:
            key = operator.itemgetter(0)
        else:
            key = lambda item, key=kwargs['key']: key(item[0])
    
        while True:
            value, i, it = min(iterables.values(), key=key)
            yield value
            try:
                iterables[i][0] = next(it)
            except StopIteration:
                del iterables[i]
                if not iterables:
                    raise
    
Sign up to request clarification or add additional context in comments.

1 Comment

This technique is also known as external sorting.
5

Based on Sorting a million 32-bit integers in 2MB of RAM using Python:

import sys
from functools import partial
from heapq import merge
from tempfile import TemporaryFile

# define sorting criteria
def second_column(line, default=float("inf")):
    try:
        return int(line.split(";", 2)[1]) # use int() for numeric sort
    except (IndexError, ValueError):
        return default # a key for non-integer or non-existent 2nd column

# sort lines in small batches, write intermediate results to temporary files
sorted_files = []
nbytes = 1 << 20 # load around nbytes bytes at a time
for lines in iter(partial(sys.stdin.readlines, nbytes), []):
    lines.sort(key=second_column) # sort current batch
    f = TemporaryFile("w+")
    f.writelines(lines)
    f.seek(0) # rewind
    sorted_files.append(f)

# merge & write the result
sys.stdout.writelines(merge(*sorted_files, key=second_column))

# clean up
for f in sorted_files:
    f.close() # temporary file is deleted when it closes

heapq.merge() has key parameter since Python 3.5. You could try mergeiter() from Martijn Pieters' answer instead or do Schwartzian transform on older Python versions:

iters = [((second_column(line), line) for line in file)
         for file in sorted_files] # note: this makes the sort unstable
sorted_lines = (line for _, line in merge(*iters))
sys.stdout.writelines(sorted_lines)

Usage:

$ python sort-k2-n.py < input.txt > output.txt

1 Comment

heapq.merge() will be added in Python 3.5.
2

You can do it with an os.system() call to the bash function sort

sort -k2 yourFile.txt 

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.