按所需顺序对大文件进行排序

Posted

技术标签:

【中文标题】按所需顺序对大文件进行排序【英文标题】:Sorting a huge file in desired order 【发布时间】:2015-08-27 13:30:10 【问题描述】:

我有以下形式的数据:

<j> <l> <n> "jd".
<K> <J> <N> <D>.
<A> <B> <D> <F>.
<E> <F> <G> "abc".    
<A> <B> <C> <D>.
<G> <k> "jd" "l".

我需要对数据进行排序,以便仅对奇数行进行排序,并根据奇数行对相应的偶数行进行排序。即文件的排序仅使用奇数行进行,即仅对以下行进行排序:

<j> <l> <n> "jd".
<A> <B> <D> <F>.
<A> <B> <C> <D>.

<A> <B> <C> <D>.
<A> <B> <D> <F>.
<j> <l> <n> "jd".

偶数行按原样获得副本。例如,上面的排序顺序将是:

<A> <B> <C> <D>.
<G> <k> "jd" "l".
<A> <B> <D> <F>.
<E> <F> <G> "abc".    
<j> <l> <n> "jd".
<K> <J> <N> <D>.

现在偶数行"&lt;G&gt; &lt;k&gt; "jd" "l"."总是出现在奇数行"&lt;A&gt; &lt;B&gt; &lt;C&gt; &lt;D&gt;."之后,偶数行"&lt;E&gt; &lt;F&gt; &lt;G&gt; "abc". "总是出现在奇数行"&lt;A&gt; &lt;B&gt; &lt;D&gt; &lt;F&gt;."之后,偶数行"&lt;K&gt; &lt;J&gt; &lt;N&gt; &lt;D&gt;."出现在奇数行&lt;j&gt; &lt;l&gt; &lt;n&gt; "jd".之后

我尝试使用带有并行选项的 linux 排序命令,因为我的文件大小为 200 GB,但这样做会扰乱奇数行的顺序。有没有办法使用 linux sort 命令或使用一些 python 程序我可以实现 200 GB 文件的预期行为

【问题讨论】:

你需要像map-reduce这样的东西 找到问题子集的解决方案:仅 4 行。然后你应该可以用 python 来做到这一点,通过分割成不同的文件。 您可能需要一种使用硬盘驱动器作为存储的高效排序算法,例如 mergesort 或类似的。 @taesu 我的问题是我找不到这样的解决方案 问题是我没有得到你的问题子集的排序算法,或者它需要太多的脑力! 【参考方案1】:

由于您使用的是 linux,我假设您已经安装了 vim(我的 ubuntu 机器上默认安装了最小版本。 如果没有,请先安装它。

我相信 vim 可以处理大文件而不会阻塞(不像记事本)

    使用 vim,将每一行与其下一行合并

input.dat

<j> <l> <n> "jd". 
<K> <J> <N> <D>.
<A> <B> <D> <F>.
<E> <F> <G> "abc".
<A> <B> <C> <D>.
<G> <k> "jd" "l".

ex input.dat -c 'g/^/j' -c 'sav! joined.dat' -c q

joined.dat:

<j> <l> <n> "jd".  <K> <J> <N> <D>.
<A> <B> <D> <F>a  <E> <F> <G> "abc".
<A> <B> <C> <D>.  <G> <k> "jd" "l".

g 是全局命令,它匹配具有行开始 (^) 的每一行(即每一行)并执行连接命令。 之后,您会将每条偶数行附加到之前的不规则行,并用两个空格分隔。

然后它保存(覆盖!)为joined.dat并退出

    像通常使用 sort 命令一样对joined.dat 文件进行排序

Sorted.dat

<A> <B> <C> <D>.  <G> <k> "jd" "l".
<A> <B> <D> <F>a  <E> <F> <G> "abc".
<j> <l> <n> "jd".  <K> <J> <N> <D>.
    “取消加入”您在第一步中加入的内容

sed 's/. /.\n/' sorted.dat &gt; finishedproduct.dat

这假设您的初始文件在每行末尾都有一个点。

注意:如果您使用 sed 输入和输出相同的文件,我相信您会得到一个空白文件。

成品.dat:

<A> <B> <C> <D>.
<G> <k> "jd" "l".
<A> <B> <D> <F>.
<E> <F> <G> "abc".
<j> <l> <n> "jd".
<K> <J> <N> <D>.

在这种情况下,sed 基本上将一个点和两个空格替换为一个点和一个换行符,有效地替换了 vim 引入的两个空格来连接行。

我知道这不是一个非常优雅的解决方案(更不用说pythonic),但它规避了“必须编写自定义程序”及其涉及的内存问题。 ;)

【讨论】:

【参考方案2】:

我同意使用 Linux sort 程序是个好主意,因为它非常高效并且可以处理比 RAM 大得多的文件排序。诀窍是在排序前后转换您的数据,以便sort 可以做您想做的事情。

您需要在一次读取两行的循环中读取数据,将两行合并为一行并将新行写入新文件。

接下来,对新文件进行排序,告诉sort 只对一行中的前 4 个键进行排序。

现在逐行读取排序后的数据,将每一行一分为二,并将分割后的数据写入最终的目标文件。

线分割和连接程序可以很容易地用 awk 或 Python 编写。我建议尝试自己编写它们,但如果您在让它们正常工作时遇到问题,我会很乐意提供帮助(我相信 SO 上的其他人也会这样做。:)

【讨论】:

以上是关于按所需顺序对大文件进行排序的主要内容,如果未能解决你的问题,请参考以下文章

v-for列表过滤和排序

如何在 QListWidget 中将项目列为组

C:对大数据进行排序;不在记忆中

如何在 Python 中对大文本文件流进行过滤和排序

对大文件大小的顺序 i/o 操作进行优化

可以对大文件排序的排序算法