标题: [文本处理] 【已解决】求助批处理文本内多列数据如何分别删重? [打印本页]
作者: 思想之翼 时间: 2022-10-24 22:56 标题: 【已解决】求助批处理文本内多列数据如何分别删重?
本帖最后由 思想之翼 于 2022-10-25 10:44 编辑
文本内数据有多列,单独各列有重复数据,如何将单独各列的重复数据删除仅保留一个。
文本数据格式如下所示:
8 4 8 3 4 6 3 3
8 3 7 4 5 5 6 3
9 3 8
结果为:
8 4 8 3 4 6 3 3
9 3 7 4 5 5 6
作者: WHY 时间: 2022-10-25 03:22
本帖最后由 WHY 于 2022-10-26 19:18 编辑
Test.bat,ANSI编码,文本中数据间的分隔符为单个Tab字符- @if(0)==(0) echo off
- type a.txt | cscript //nologo //e:jscript "%~f0" > b.txt
- pause & exit/b
- @end
-
- Array.prototype.contains = function(s){ //添加contains方法
- for( var i = 0; i < this.length; i++ ){
- if( s == this[i] ) return true;
- }
- return false;
- }
-
- var out = [], max = 0;
-
- while( !WSH.StdIn.AtEndOfStream ){
- var arrLine = WSH.StdIn.ReadLine().split(/\t/); //按单个Tab字符分割成数组
- for( var i = 0; i < arrLine.length; i++ ){
- if( out[i] instanceof Array == false ){ //out[i]不是数组类型
- out[i] = []; //初始化
- }else if( out[i].contains(arrLine[i]) ){
- continue; //out[i]去重复
- }
- out[i].push(arrLine[i]); //数据放入二维数组
- }
- }
-
- for( var i = 0; i < out.length; i++ ){
- max = max < out[i].length ? out[i].length : max; //求最大行数
- }
-
- for( var i = 0; i < max; i++ ){ //行
- var str = '';
- for( var j = 0; j < out.length; j++ ){ //列
- str += ( out[j][i] == undefined ? '' : out[j][i] ) + '\t';
- }
- WSH.Echo(str);
- }
复制代码
Test.ps1 右键使用 PowerShell 运行- $srcFile = 'a.txt'; #修改前的文件名
- $dstFile = 'b.txt'; #修改后的文件名
-
- $out = [Collections.ArrayList]@(); #数组,存放行、列数据
- $ret = [Collections.ArrayList]@(); #数组,返回处理结果
- $max = 0; #最大行数
-
- forEach( $strLine In [IO.File]::ReadAllLines($srcFile) ){
- $arrLine = $strLine.Split("`t"); #按单个Tab字符分割成数组
- for( $i=0; $i -lt $arrLine.Count; $i++ ){
- if( $out[$i] -isNot [Collections.ArrayList] ){ #如果$out[$i]不是数组类型
- $null = $out.Add( [Collections.ArrayList]@() ); #数组$out添加$out[$i]
- } elseIf( $out[$i].IndexOf($arrLine[$i]) + 1 ){
- continue; #数组$out[$i]去重
- }
- $null = $out[$i].Add( $arrLine[$i] ); #数组$out[$i]存放行列数据
- }
- }
-
- for( $i=0; $i -lt $out.Count; $i++ ){
- if( $max -lt $out[$i].Count ){ $max = $out[$i].Count; } #计算最大行数
- }
-
- for( $i=0; $i -lt $max; $i++ ){ #遍历行
- $str = '';
- for( $j=0; $j -lt $out.Count; $j++ ){ #遍历列
- $str += $out[$j][$i] + "`t";
- }
- $null = $ret.Add($str); #存放结果
- }
-
- [IO.File]::WriteAllLines($dstFile, $ret); #输出
复制代码
在我的Win10电脑上,测试2000行10列的文本,PowerShell比js快很多,PS=0.3秒,js=3.5秒
一直以为文本处理js比PS快,出乎意料。
测试生成文本:- @echo off
- setlocal enabledelayedexpansion
- (for /L %%i in (1,1,2000) do (
- set "s="
- for /L %%j in (1,1,10) do (
- set /a r = !Random! %% 2000
- set "s=!s!!r! "
- )
- echo;!s:~0,-1!
- ))>a.txt
复制代码
作者: hfxiang 时间: 2022-10-25 10:29
本帖最后由 hfxiang 于 2022-10-25 13:10 编辑
把待处理文件保存为“a.txt”,编码格式为ANSI,用第3方工具gawk( http://bcn.bathome.net/tool/4.1.0/gawk.exe )可实现:- type a.txt|gawk -vORS="\t" "{max=max>NF?max:NF;for(i=1;i<=max;i++)a[NR,i]=$i}END{for(i=1;i<=max;i++){for(j=1;j<=NR;j++)if(!a[j,i]||!x[a[j,i],i]++)print a[j,i];printf \"\n\"}}"|gawk -F"\t" -vORS="\t" "{max=max>NF?max:NF;for(i=1;i<=max;i++)a[NR,i]=$i}END{for(i=1;i<=max;i++){for(j=1;j<=NR;j++){print (a[j,i]==\"\")?\"\":a[j,i]}printf \"\n\"}}"
复制代码
作者: 思想之翼 时间: 2022-10-26 14:13
本帖最后由 思想之翼 于 2022-10-26 16:41 编辑
回复 2# WHY
感谢帮助!欲在标红处添加循环语句,出错。恳望指点!
type a.txt | cscript //nologo //e:jscript "%~f0" > b.txt
@echo off
For f = 1 to 441
For z = 1 to 100
@if(0)==(0) echo off
type e:\数据1\" & Right("00" & f, 3) & "\" & Right("00" & z, 3) & ".txt | cscript //nologo //e:jscript "%~f0" > e:\数据2\ "& Right("00" & f, 3) & "\" & Right("00" & z, 3) &" .txt
作者: WHY 时间: 2022-10-26 19:27
回复 4# 思想之翼
Test.ps1 右键使用 PowerShell 运行- Function RemoveDuplicateData($file){
- $out = [Collections.ArrayList]@(); #数组,存放行、列数据
- $max = 0; #最大行数
-
- forEach( $strLine In [IO.File]::ReadAllLines($file) ){
- $arrLine = $strLine.Split("`t"); #按单个Tab字符分割成数组
- for( $i=0; $i -lt $arrLine.Count; $i++ ){
- if( $out[$i] -isNot [Collections.ArrayList] ){ #如果$out[$i]不是数组类型
- $null = $out.Add( [Collections.ArrayList]@() ); #数组$out添加$out[$i]
- } elseIf( $out[$i].IndexOf($arrLine[$i]) + 1 ){
- continue; #数组$out[$i]去重
- }
- $null = $out[$i].Add( $arrLine[$i] ); #数组$out[$i]存放行列数据
- }
- }
-
- for( $i=0; $i -lt $out.Count; $i++ ){
- if( $max -lt $out[$i].Count ){ $max = $out[$i].Count; } #计算最大行数
- }
-
- for( $i=0; $i -lt $max; $i++ ){ #遍历行
- $str = '';
- for( $j=0; $j -lt $out.Count; $j++ ){ #遍历列
- $str += $out[$j][$i] + "`t";
- }
- $null = $result.Add($str); #存放结果
- }
- }
-
- for( $i = 1; $i -le 441; $i++ ){
- for( $j = 1; $j -le 100; $j++ ){
- $srcFile = 'E:\数据1\' + ('' + $i).PadLeft(3, '0') + '\' + ('' + $j).PadLeft(3, '0') + '.txt';
- $dstFile = 'E:\数据2\' + ('' + $i).PadLeft(3, '0') + '\' + ('' + $j).PadLeft(3, '0') + '.txt';
- if( ![IO.File]::Exists($srcFile) ) { continue; }
- $result = [Collections.ArrayList]@();
- RemoveDuplicateData $srcFile;
- [IO.File]::WriteAllLines($dstFile, $result); #写文件
- }
- }
-
- echo 'Done';
- [Console]::ReadLine();
复制代码
作者: WHY 时间: 2022-10-26 19:30
Test.js- var fso = new ActiveXObject('Scripting.FileSystemObject');
-
- Array.prototype.contains = function(s){ //添加contains方法
- for( var i = 0; i < this.length; i++ ){
- if( s == this[i] ) return true;
- }
- return false;
- }
-
- for( var i = 1; i <= 441; i++ ){
- for( var j = 1; j <= 100; j++ ){
- var srcFile = 'e:\\数据1\\' + ('00' + i).slice(-3) + '\\' + ('00' + j).slice(-3) + '.txt';
- var dstFile = 'e:\\数据2\\' + ('00' + i).slice(-3) + '\\' + ('00' + j).slice(-3) + '.txt';
- if( !fso.FileExists(srcFile) ) continue;
- var result = [];
- removeDuplicateData(srcFile);
- fso.OpenTextFile(dstFile, 2, true).Write( result.join('\r\n') );
- }
- }
-
- function removeDuplicateData(file){
- var out = [], max = 0;
- var objFile = fso.OpenTextFile(file, 1);
-
- while( !objFile.AtEndOfStream ){
- var arrLine = objFile.ReadLine().split('\t'); //按单个Tab字符分割成数组
- for( var i = 0; i < arrLine.length; i++ ){
- if( out[i] instanceof Array == false ){ //out[i]不是数组类型
- out[i] = []; //初始化
- }else if( out[i].contains(arrLine[i]) ){
- continue; //out[i]去重复
- }
- out[i].push(arrLine[i]); //数据放入二维数组
- }
- }
-
- for( var i = 0; i < out.length; i++ ){
- max = max < out[i].length ? out[i].length : max; //求最大行数
- }
-
- for( var i = 0; i < max; i++ ){ //行
- var str = '';
- for( var j = 0; j < out.length; j++ ){ //列
- str += ( out[j][i] == undefined ? '' : out[j][i] ) + '\t';
- }
- result.push(str);
- }
- }
-
- WSH.Echo('Done');
复制代码
作者: WHY 时间: 2022-10-29 14:04
想来想去总觉得2#哪里不对劲,今天终于发现了问题所在:添加的contains方法效率极其低下,每个数据都要调用一次contains,每次调用都要for循环遍历,总循环次数成几何级增加。
js改用散列数组代替自定义的contains方法:- var t = (new Date()).getTime();
-
- var out = [], res = [], max = 0;
- var map = [];
- var fso = new ActiveXObject('Scripting.FileSystemObject');
- var objFile = fso.OpenTextFile('a.txt', 1);
-
- while( !objFile.AtEndOfStream ){
- var arrLine = objFile.ReadLine().split('\t'); //按单个Tab字符分割成数组
- var len = arrLine.length;
- for( var i = 0; i < len; i++ ){
- if( out[i] instanceof Array == false ){ //out[i]不是数组类型
- out[i] = []; //初始化
- map[i] = [];
- }else if( map[i][arrLine[i]] ){
- continue; //out[i]去重复
- }
- map[i][arrLine[i]] = true;
- out[i].push(arrLine[i]); //数据放入二维数组
- }
- }
-
- for( var i = 0; i < out.length; i++ ){
- max = max < out[i].length ? out[i].length : max; //求最大行数
- }
-
- for( var i = 0; i < max; i++ ){ //行
- var str = '';
- for( var j = 0; j < out.length; j++ ){ //列
- str += ( out[j][i] == undefined ? '' : out[j][i] ) + '\t';
- }
- res.push(str);
- }
-
- fso.OpenTextFile('b.txt', 2, true).Write( res.join('\r\n') );
-
- WSH.Echo((new Date()).getTime() - t);
复制代码
PowerShell改用HashTable containsKey方法代替数组IndexOf方法:- $t = get-Date;
- $srcFile = 'a.txt'; #修改前的文件名
- $dstFile = 'b.txt'; #修改后的文件名
-
- $out = [Collections.ArrayList]@(); #数组,存放行、列数据
- $ret = [Collections.ArrayList]@(); #数组,返回处理结果
- $map = [Collections.ArrayList]@(); #数组,存放HashTable
- $max = 0; #最大行数
-
- forEach( $strLine In [IO.File]::ReadAllLines($srcFile) ){
- $arrLine = $strLine.Split("`t"); #按单个Tab字符分割成数组
- for( $i=0; $i -lt $arrLine.Count; $i++ ){
- if( $out[$i] -isNot [Collections.ArrayList] ){ #如果$out[$i]不是数组类型
- $null = $out.Add( [Collections.ArrayList]@() ); #数组$out添加$out[$i]
- $null = $map.Add( @{} ); #数组$map添加$map[$i]
- } elseIf( $map[$i].ContainsKey($arrLine[$i]) ){
- continue; #数组$out[$i]去重
- }
- $null = $out[$i].Add( $arrLine[$i] ); #数组$out[$i]存放列数据
- $map[$i].Add( $arrLine[$i], $true ); #添加到HashTable
- }
- }
-
- for( $i=0; $i -lt $out.Count; $i++ ){
- if( $max -lt $out[$i].Count ){ $max = $out[$i].Count; } #计算最大行数
- }
-
- for( $i=0; $i -lt $max; $i++ ){ #遍历行
- $str = '';
- for( $j=0; $j -lt $out.Count; $j++ ){ #遍历列
- $str += $out[$j][$i] + "`t";
- }
- $null = $ret.Add($str); #存放结果
- }
-
- [IO.File]::WriteAllLines($dstFile, $ret); #输出
-
- ((get-Date) - $t).TotalSeconds
- [Console]::ReadLine();
复制代码
测试10000行10列的文本,两个脚本用时都在 0.5s 以内,基本算是正常了。
生成测试文本:- @echo off
- setlocal enabledelayedexpansion
- (for /L %%i in (1,1,10000) do (
- set "s="
- for /L %%j in (1,1,10) do (
- set /a r = !Random! %% 8000
- set "s=!s!!r! "
- )
- echo;!s:~0,-1!
- )) > a.txt
复制代码
欢迎光临 批处理之家 (http://bbs.bathome.net/) |
Powered by Discuz! 7.2 |