Перемешать несколько файлов в одном порядке

2

Настроить:

У меня 50 файлов, каждая из которых содержит 25000 строк.

Делать:

Мне нужно перетасовать все их "в том же порядке". Например:

Если перед перемещением:

File 1  File 2  File 3
A       A       A
B       B       B
C       C       C

то после перетасовки я должен получить:

File 1  File 2  File 3
B       B       B
C       C       C
A       A       A

т.е. соответствующие строки в файлах следует перетасовывать в том же порядке.

Кроме того, перетасовка должна быть детерминированной, т.е. Если я даю файл A в качестве входного сигнала, он должен всегда производить такой же перетасованный вывод.

Я могу написать программу Java, чтобы сделать это, возможно, сценарий. Что-то вроде, перетасовать число от 1 до 25000 и сохранить это в файле, скажем, shuffle_order. Затем просто обрабатывайте один файл и заказывайте существующие строки в соответствии с shuffle_order. Но есть ли лучший/быстрый способ сделать это?

Пожалуйста, дайте мне знать, если вам нужна дополнительная информация.

  • 0
    Большая проблема, с которой вы столкнулись (но, возможно, еще не заметили), заключается в том, как вы поместите ОДИН файл в заранее установленный порядок ... особенно если вы не можете предположить, что весь файл может храниться в памяти одновременно. Вам может понадобиться создать «промежуточные» файлы (с каждой строкой, в которой предопределенный порядок должен иметь префикс к строке), а затем проходить через них в режиме пинг / понг, пока вы, наконец, не получите файл в порядке.
  • 0
    Измените свой вопрос, если вам нужно обрабатывать «файл не помещается в память», и я могу дать вам рекомендации по процессу «сортировки слиянием».
Теги:
random
shuffle

2 ответа

1

В следующем используются только базовые команды bash. Принцип:

  • генерировать случайный порядок (числа)
  • заказать все файлы в этом заказе

код

#!/bin/bash
case "$#" in
    0) echo "Usage: $0 files....." ; exit 1;;
esac

ORDER="./.rand.$$"
trap "rm -f $ORDER;exit" 1 2
count=$(grep -c '^' "$1")

let odcount=$(($count * 4))
paste -d" " <(od -A n -N $odcount -t u4 /dev/urandom | grep -o '[0-9]*') <(seq -w $count) |\
    sort -k1n | cut -d " " -f2 > $ORDER

#if your system has the "shuf" command you can replace the above 3 lines with a simple
#seq -w $count | shuf > $ORDER

for file in "$@"
do
    paste -d' ' $ORDER $file | sort -k1n | cut -d' ' -f2-  > "$file.rand"
done

echo "the order is in the file $ORDER"  # remove this line
#rm -f $ORDER                           # and uncomment this
                                        # if dont need preserve the order

paste -d "  " *.rand   #remove this line - it is only for showing test result

из входных файлов:

A  B  C
--------
a1 a2 a3
b1 b2 b3
c1 c2 c3
d1 d2 d3
e1 e2 e3
f1 f2 f3
g1 g2 g3
h1 h2 h3
i1 i2 i3
j1 j2 j3

сделает A.rand B.rand C.rand следующим примером контента

g1 g2 g3
e1 e2 e3
b1 b2 b3
c1 c2 c3
f1 f2 f3
j1 j2 j3
d1 d2 d3
h1 h2 h3
i1 i2 i3
a1 a2 a3

реальное тестирование - создание 50 файлов с 25k строк

line="Consequatur qui et qui. Mollitia expedita aut excepturi modi. Enim nihil et laboriosam sit a tenetur."
for n in $(seq -w 50)
do
    seq -f "$line %g" 25000 >file.$n
done

запуск скрипта

bash sorter.sh file.??

результат на моей записной книжке

real     1m13.404s
user     0m56.127s
sys      0m5.143s
0

Вероятно, очень неэффективно, но попробуйте ниже:

#!/bin/bash

arr=( $(for i in {1..25000}; do
    echo "$i"
done | shuf) )


for file in files*; do
    index=0
    new=$(while read line; do
        echo "${arr[$index]} $line"
        (( index++ ))
    done < "$file" | sort -h | sed 's/^[0-9]\+ //')
    echo "$new" > "$file"
done

Ещё вопросы

Сообщество Overcoder
Наверх
Меню