Случайно смешивать строки из файла с 3 миллионами строк - PullRequest
24 голосов
/ 06 января 2011

Все есть в названии. Мне интересно, если кто-нибудь знает, быстро и с разумной памятью требует случайного смешивания всех строк файла 3 миллиона строк. Я предполагаю, что это невозможно с помощью простой команды vim, поэтому любой простой скрипт использует Python. Я пытался с python, используя генератор случайных чисел, но не смог найти простой выход.

Ответы [ 10 ]

41 голосов
/ 06 января 2011

В Python занимает всего несколько секунд:

>>> import random
>>> lines = open('3mil.txt').readlines()
>>> random.shuffle(lines)
>>> open('3mil.txt', 'w').writelines(lines)
30 голосов
/ 06 января 2011
import random
with open('the_file','r') as source:
    data = [ (random.random(), line) for line in source ]
data.sort()
with open('another_file','w') as target:
    for _, line in data:
        target.write( line )

Это должно сделать это.3 миллиона строк поместятся в память большинства компьютеров, если только они не ОГРОМНЫ (более 512 символов).

16 голосов
/ 13 мая 2016

Я только что попробовал это для файла с 4.3M строк, и самая быстрая вещь была команда 'shuf' в Linux. Используйте это так:

shuf huge_file.txt -o shuffled_lines_huge_file.txt

Потребовалось 2-3 секунды, чтобы закончить.

3 голосов
/ 06 января 2011

Во многих системах команда оболочки sort требует -R для рандомизации своего ввода.

2 голосов
/ 06 января 2011

Вот еще одна версия

В оболочке используйте это.

python decorate.py | sort | python undecorate.py

decorate.py

import sys
import random
for line in sys.stdin:
    sys.stdout.write( "{0}|{1}".format( random.random(), line ) )

undecorate.py

import sys
for line in sys.stdin:
    _, _, data= line.partition("|")
    sys.stdout.write( line )

практически не использует память.

1 голос
/ 06 января 2011

Если вы не хотите загрузить все в память и отсортировать ее там, у вас есть для хранения строк на диске при выполнении случайной сортировки. Это будет очень медленно.

Вот очень простая, глупая и медленная версия. Обратите внимание, что это может занять удивительное количество дискового пространства, и это будет очень медленно. Я запустил его с 300 000 строк, и это занимает несколько минут. 3 миллиона строк вполне могут занять час. Итак: делай это в памяти. В самом деле. Он не такой большой.

import os
import tempfile
import shutil
import random
tempdir = tempfile.mkdtemp()
print tempdir

files = []
# Split the lines:
with open('/tmp/sorted.txt', 'rt') as infile:
    counter = 0    
    for line in infile:
        outfilename = os.path.join(tempdir, '%09i.txt' % counter)
        with open(outfilename, 'wt') as outfile:
            outfile.write(line)
        counter += 1
        files.append(outfilename)

with open('/tmp/random.txt', 'wt') as outfile:
    while files:
        index = random.randint(0, len(files) - 1)
        filename = files.pop(index)
        outfile.write(open(filename, 'rt').read())

shutil.rmtree(tempdir)

Другой версией будет сохранение файлов в базе данных SQLite и случайное выделение строк из этой базы данных. Это, вероятно, будет быстрее, чем это.

1 голос
/ 06 января 2011

Это то же самое, что и г-н Кугельман, но с использованием встроенного в Python интерфейса vim:

:py import vim, random as r; cb = vim.current.buffer ; l = cb[:] ; r.shuffle(l) ; cb[:] = l
0 голосов
/ 12 июня 2019

Это сделает свое дело: мое решение даже не использует случайное, и оно также удалит дубликаты.

import sys
lines= list(set(open(sys.argv[1]).readlines()))
print(' '.join(lines))

в оболочке

python shuffler.py nameoffilestobeshuffled.txt > shuffled.txt
0 голосов
/ 11 февраля 2018

Следующий код Vimscript может использоваться для замены строк:

function! Random()                                                       
  let nswaps = 100                                                       
  let firstline = 1                                                     
  let lastline = 10                                                      
  let i = 0                                                              
  while i <= nswaps                                                      
    exe "let line = system('shuf -i ".firstline."-".lastline." -n 1')[:-2]"
    exe line.'d'                                                         
    exe "let line = system('shuf -i ".firstline."-".lastline." -n 1')[:-2]"
    exe "normal! " . line . 'Gp'                                         
    let i += 1                                                           
  endwhile                                                               
endfunction

Выберите функцию в визуальном режиме и введите :@", затем выполните ее с помощью :call Random()

0 голосов
/ 08 февраля 2018

Вот еще один способ использования random.choice , это также может обеспечить некоторое постепенное освобождение памяти, но с худшим Big-O :)

...