我有一个名为test.txt的文件,看起来像这样:
Line 1
Line 2
Line 3
Line 3
Line 3
Line 4
Line 8
我需要一些代码,这将随机这些行**,但保证**,相同的文字不能出现在连续行即“行3”必须分裂,而不是出现两次,甚至三次在一排。
我已经看到了这个问题的许多变化,但到目前为止,没有一个处理重复的行。
到目前为止,我已经测试了以下内容:
shuf test.txt
awk 'BEGIN{srand()}{print rand(), $0}' test.txt | sort -n -k 1 | awk 'sub(/\S /,"")'*
awk 'BEGIN {srand()} {print rand(), $0}' test.txt | sort -n | cut -d ' ' -f2-
cat test.txt | while IFS= read -r f; do printf "%05d %s\n" "$RANDOM" "$f"; done | sort -n | cut -c7-
perl -e 'print rand()," $_" for <>;' test.txt | sort -n | cut -d ' ' -f2-
perl -MList::Util -e 'print List::Util::shuffle <>' test.txt
所有这些都使文件中的行随机化,但通常最终相同的行在文件中连续出现。
有什么办法可以让我这么做吗?
这是编辑前的数据。您可以看到数字82576483
出现在连续的行中
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>83476098</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441754</ORD-AUTH-C><ORD-AUTH-V>94.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5759148</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576786</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>24.79</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576324</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441754</ORD-AUTH-C><ORD-AUTH-V>98.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5759148</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576113</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>28.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82590483</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>25.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576883</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>17.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>83476483</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
**注意:**添加了提示以突出显示感兴趣的行;数据文件中不存在提示
这就是我需要在数字82576483
分散在文件中而不是在连续行上时发生的情况
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>83476098</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441754</ORD-AUTH-C><ORD-AUTH-V>94.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5759148</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576786</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>24.79</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576324</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441754</ORD-AUTH-C><ORD-AUTH-V>98.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5759148</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576113</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>28.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82590483</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>25.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>82576883</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>17.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>83476483</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
REC-TYPE-C>CHARGE INVOICE</REC-TYPE-C><CUST-ACNT-N>**82576483**</CUST-ACNT-N><CUST-NAME-T>TEST TEN</CUST-NAME-T><ORD-AUTH-C>0044441552</ORD-AUTH-C><ORD-AUTH-V>21.99</ORD-AUTH-V><OUT-DOCM-D>01/09/2023</OUT-DOCM-D><ORD-N>5758655</ORD-N>
7条答案
按热度按时间ylamdve61#
一种有效的方法,至少与重复随机尝试相比:
1.对所有唯一字符串进行排序
1.对于每个重复,
1.确定它可以放置的位置。
1.随便挑一个
1.在那里插入副本。
(Just使用
perl -e'...'
Package 以从shell运行。经过测试。可能有更好的方法。
pod7payv2#
一般方法:
linecnt[]
)来记录一行被看到的次数linecnt[]
分成两个独立的普通数组:single[1]=<lineX>; single[2]=<lineY>
和multi[1]=<lineA_copy1>; multi[2]=<lineA_copy2>; multi[3]=<lineB_copy1>
single[] / multi[]
)散布我们的打印(即,打印random(single[])
,打印randome(multi[])
,打印random(single[])
,打印randome(multi[])
);**注意:**显然不是 * 真正 * 随机的,但这允许我们最大限度地分离重复的机会,同时限制CPU开销(即,不需要重复 Shuffle 希望一个'随机'排序,分裂重复)single[]
条目,则打印random(single[])
multi[]
条目离开然后打印random(multi[]
);**注意:*假设OP的注解re:tough!!
* 意味着如果这是所有剩下的,可以连续打印重复一个
awk
的想法:注意:
srand()
不是真正的随机(例如,两次快速连续的运行可以生成相同的精确输出)srand()
的操作系统级种子)运行OP的样本数据集:
注意:
single[] / multi[]
条目块和 b) 第2个完成剩余single[]
条目块处理重复的示例...
运行
awk
脚本的结果:注意:
single[] / multi[]
条目块和 b) 第2个完成剩余multi[]
条目块qcuzuvrc3#
ruby有一些简洁的语法。
https://stackoverflow.com/a/65843200可以根据您的数据轻松修改:
gywdnpxw4#
另一种方法:首先打乱行,然后逐行,收集重复的内容。对于每一行,检查现有的重复内容,如果可能的话,将其放入。在输入以这种方式处理后,然后从头开始检查结果,尝试放置剩余的重复内容
它将发现的重复存储在一个数组中,并检查每行是否可以插入现有的重复。它使用一个辅助掩码数组来标记已使用的重复索引。
注意到
然而,dupes的数组应该很短,而且大多数时候不会搜索整个数组。所以如果输入不是很大,有很多dupes,这应该会很好。
用不同的输入进行测试,有多行的许多重复,但需要更多的测试。(至少,添加基本的诊断打印并重复运行-它每次都会 Shuffle ,所以重复运行会有帮助-并检查输出。)
y4ekin9u5#
使用任何awk:
所以,在一次尝试中,它尝试了1000次,(
maxIters
)从未处理的行集合中随机找到下一行输出,该行与它刚刚添加到输出中的行不同,但最终仍可能失败,它尝试了1000次(maxAttempts
)来产生输出。这仍然可能失败-如果你愿意,可以增加这些值,但你仍然可以得到无法按照你喜欢的方式组织的输出(例如,只有两行输入,其中两行都是相同的)。您可以通过更改以下代码来提高效率并增加成功的机会:
创建/使用仅由键+行组成的二级数组,这些行与刚刚处理的行不具有相同的键,因此我们不需要在其上方进行
if ( tmpKeys[idx] != prev )
测试,并且当有其他键可供选择时,我们不会冒idx = int(1+rand()*numLines)
以上随机找到相同键1000次的风险。该增强将作为练习:-)。ih99xse16#
使用TXR Lisp:
代码:
这不是一个正确的算法,因为如果输入具有高的重复率,则存在正确的排序,例如:
它将不一致地产生分开重复的两个
2 1 2
顺序。算法的主要流程是
flow
形式。从标准输入中获取行,然后通过sort-group
,sort-group
将重复的行分组并排序,得到一个字符串列表的列表。不重复的行是长度为1的列表。我们随机 Shuffle 这个列表的列表,这意味着重复的列在一起。然后,我们使用两个通道来分发副本,这两个通道使用一个名为
dupstack
的向量。在第一次传递中,我们Map列表的列表,使得单例通过
distrib
传递,重复通过distrib-push
传递。这以下面描述的方式移动重复。在此传递之后,一些项保留在dupstack
中;所以列表的列表并没有所有的项目。我们进行了另一次传递,这次只是将每个列表传递给distrib
,它将项目分发到dupstack
之外。dupstack
是列表的向量,列表是重复行的列表。例如[dupstack 0]
可能包含("Line 3" "Line 3" "Line 3")
等。distrib
的工作原理是:它扫过dupstack,从每个元素的前面弹出一个元素,并将其附加到输入列表,返回该输入列表。如果我们使用此操作进行Map,这意味着我们访问的每个列表,我们从每个重复集合中添加一个项目。每次扫过这个堆栈后,我们使用(upd dupstack (remq nil))
压缩它,以清除它已变为空的列表。函数
distrib-push
用于处理包含多个元素的列表时的第一遍(由Lispcdr
函数返回非空表示)。distrib-push
所做的是用一个空列表调用distrib
,只是为了收集任何可用的副本,每一个都有一个。这些从dupstack
中挑选出来的项目然后 * 替换 * 当前的项目。这些项目,相同的字符串,被推入重复堆栈中的新槽中。aydmsdu97#
下面是一个示例文件:
将第一列定义为键,并限制每个键都不能与同一个键相邻,然后随机化文件。在这个限制下,结果将是随机的,因为
A
的个数比B
的个数多,并且A必须位于序列的开头。(奇数项的偶数索引数比奇数项的多,因为0的奇偶性是偶数。)一般做法是:
1.将所有相似的关键行组合在一起;
1.从输入线的组中随机选择奇数或偶数,以便分配所定义的组;
1.随机选择剩余的行进行输出。
这在Ruby中很容易做到:
图纸:
这是很容易改变的,以适应OP示例输入。只有键和输出行的正则表达式被改变:
图纸: