Chinaunix

标题: 提取行中不同的字符串的行 [打印本页]

作者: bmne    时间: 2017-05-16 20:19
标题: 提取行中不同的字符串的行



共四列,
要求:提取行中(各列中)不同的字符串的行

1 2 3 4
a b c d
1 1 1 1
1 1 2 2
1 1 2 3
1 2 3 3
1 2 3 1
1 2 2 3
1 2 3 3
1 1 1 2
1 2 2 2
输出
1 2 3 4
a b c d

请给个效率稍高一点的命令

这个有点慢
awk '($1!=$2&&$1!=$3&&$1!=$4&&$2!=$3&&$2!=$4&&$3!=$4)'


谢谢





作者: baby_神    时间: 2017-05-16 20:34
本帖最后由 baby_神 于 2017-05-16 20:36 编辑

awk '{for(i=1;i<=NF;i++)a[$i];if(length(a)==NF)print $0;delete a}' file
作者: sunzhiguolu    时间: 2017-05-16 20:53
  1. import io.Source

  2. for(s <- Source.fromFile(args(0)).getLines){
  3.         val lst = s.split(raw"\s+")
  4.         if(lst.length == lst.distinct.length) println(s)
  5. }
复制代码

作者: baby_神    时间: 2017-05-16 20:57
py版本
  1. a = """
  2. 1 2 3 4
  3. a b c d
  4. 1 1 1 1
  5. 1 1 2 2
  6. 1 1 2 3
  7. 1 2 3 3
  8. 1 2 3 1
  9. 1 2 2 3
  10. 1 2 3 3
  11. 1 1 1 2
  12. 1 2 2 2
  13. """

  14. for i in a.split("\n"):
  15.     if len(set(i)) == 5:
  16.         print(i)
复制代码

作者: haooooaaa    时间: 2017-05-16 21:18
  1. awk '!a[$1]++&&!b[$2]++&&!c[$3]++&&!d[$4]++'
复制代码

作者: 799029078    时间: 2017-05-16 21:39
厉害了

作者: bmne    时间: 2017-05-17 06:34
回复 2# baby_神


还行。比我一楼的要稍快一点点。
谢谢,辛苦

real     42m43.830s
user    42m16.700s
sys     0m9.750s





作者: bmne    时间: 2017-05-17 06:41
本帖最后由 bmne 于 2017-05-17 06:53 编辑

回复 5# haooooaaa


大牛,我试了小文件,没问题。
但,换成大文件后,运行6分多钟就结束运行了,但没出最终输出结果(输出结果不正确)。反复几次都这样,我没找到原因

real    6m12.323s
user    6m4.730s
sys     0m3.291s




作者: 关阴月飞    时间: 2017-05-17 08:40
回复 5# haooooaaa

这个作用域太广了,全文本范围去重,本意应该是以行去重就行
作者: blackold    时间: 2017-05-17 09:10
一定要awk?
try:

  1. sed '/\<\(.*\)\>.*\<\1\>/d;' urfile
复制代码

  1. grep -Ev '\<(.*)\>.*\<\1\>' urfile
复制代码





作者: blackold    时间: 2017-05-17 09:11
本帖最后由 blackold 于 2017-05-17 09:45 编辑

发重了。


awk 居然不支持后引用,太烂了,不要用它了。
作者: bmne    时间: 2017-05-17 13:39
回复 10# blackold


大牛好

你太忙,没想到有时间出手。谢谢

实话实说。这两个命令效率慢的吓人。实战中运行结束要5个多小时(估计)。运行途中让我停止了

我没想到grep也会这么慢



作者: 本友会机友会摄友会    时间: 2017-05-17 15:23
提示: 作者被禁止或删除 内容自动屏蔽
作者: bmne    时间: 2017-05-17 17:50
本帖最后由 bmne 于 2017-05-17 17:56 编辑

回复 10# blackold


大牛

我这次的实战样本是  (每一行中)纯字母+空格,没有其它,就是稍大些(近15GB)。每一组字符串最长超不过7个字符。换言之,极端情况每一行最多共30个字符。

我运行前先dos2unix  然后 我前面必须LANG=C再运行。因我以前吃过亏,我已长记性。总之,前期该做的工作已准备好

然后,再运行你的命令的。同等条件下目前较理想的是1、2楼的awk  运行时间估计你也看到了

如果有点时间,麻烦你看看grep的那个(我自己认为它应该效率高些)。如果太忙,就到此吧。我凑合着用awk即可

不好意思




作者: blackold    时间: 2017-05-18 08:32
回复 15# bmne

对的。

要效率的话,最好不用正则。正则本身就是循环,尤其是后引用。

作者: dahe_1984    时间: 2017-05-18 10:37
行中(各列中)不同?

题目啥意思?我咋没看懂呢?
行不同,列也不同?
作者: bmne    时间: 2017-05-18 11:05
回复 17# dahe_1984


每一行的不同,各个字符串的不同
因为中间有空格,所以我括号说明了一下,同一行中的各列的不同
若再没看明白,就看看列举的数据



作者: 本友会机友会摄友会    时间: 2017-05-18 12:54
提示: 作者被禁止或删除 内容自动屏蔽
作者: bmne    时间: 2017-05-18 14:02
本帖最后由 bmne 于 2017-05-18 15:12 编辑

回复 19# 本友会机友会摄友会


知道你用心了,大牛级人物,也浪费脑细胞了。谢谢,辛苦了

老师只告诉我去买一瓶醋,突然半路遇到一个熟人,非要让我再买瓶酱油,可我没带钱。 不好意思,开个玩笑

(另,若非要让我说实话, @jason680    对这方面shell研究深)




作者: dahe_1984    时间: 2017-05-18 14:22
回复 7# bmne

$ time perl find.pl

1 2 3 4
a b c d

real    0m0.261s
user    0m0.031s
sys     0m0.030s


作者: dahe_1984    时间: 2017-05-18 14:23
bmne 发表于 2017-05-17 06:34
回复 2# baby_神

$ time perl find.pl

1 2 3 4
a b c d

real    0m0.261s
user    0m0.031s
sys     0m0.030s

发给你测试的数据呗。


作者: bmne    时间: 2017-05-18 14:29
回复 21# dahe_1984


不好意思。我帖子里面标注的时间,是实战的结果。不是我一楼数据的



作者: dahe_1984    时间: 2017-05-18 14:34
回复 23# bmne

实战数据发下呗,正好我闲着没事,自己搞搞
作者: bmne    时间: 2017-05-18 14:38
回复 24# dahe_1984

太大了。给不了你(15GB)

你试一下2楼的命令。这是我测的

real    0m0.016s
user    0m0.000s
sys     0m0.015s




作者: dahe_1984    时间: 2017-05-18 14:39
回复 25# bmne

切1G或者几百M,数据太小看不出什么
作者: dahe_1984    时间: 2017-05-18 14:42
nxf26935@star:~$ time perl find.pl
1 2 3 4
a b c d



real    0m0.005s
user    0m0.000s
sys     0m0.004s

作者: dahe_1984    时间: 2017-05-18 14:42
服务器上跑的
作者: bmne    时间: 2017-05-18 14:44
回复 26# dahe_1984

请放出你的手中的命令来可以?看看杀手锏

谢谢

作者: dahe_1984    时间: 2017-05-18 14:47
抓图如上,

Capture.GIF (4.34 KB, 下载次数: 0)

Capture.GIF

作者: dahe_1984    时间: 2017-05-18 14:49
这里的附件怎么上传才能看到?

Capture.GIF (4.34 KB, 下载次数: 18)

Capture.GIF

作者: dahe_1984    时间: 2017-05-18 15:05
#perl!

use strict;

while(<DATA>){
my @tmpArr;
my $flag = 1;
my @found = "";

    @tmpArr = split(/\s+/,$_);

    foreach (@tmpArr) {
        if("@found" =~ $_)
        {
            $flag = 0;
            next;
        } else {
            push(@found, $_);
        }
    }
   
    if($flag == 1) {
        printf "@found\n";
        @found = "";
    }
}

__DATA__
1 2 3 4
a b c d
1 1 1 1
1 1 2 2
1 1 2 3
1 2 3 3
1 2 3 1
1 2 2 3
1 2 3 3
1 1 1 2
1 2 2 2



作者: dahe_1984    时间: 2017-05-18 15:06
估计只判断自身而不push新的数组会更快一些。
作者: bmne    时间: 2017-05-18 15:09
回复 33# dahe_1984

谢谢,辛苦
作者: 本友会机友会摄友会    时间: 2017-05-18 17:40
提示: 作者被禁止或删除 内容自动屏蔽
作者: elu_ligao    时间: 2017-05-19 11:18
本帖最后由 elu_ligao 于 2017-05-19 11:22 编辑

试试这个
  1. awk '{for(i=1;i<=NF;++i)if(a[$i]++)next; delete a}1' file
复制代码

作者: elu_ligao    时间: 2017-05-19 11:23
编辑没用, 应该
awk '{delete a; for(i=1;i<=NF;++i)if(a[$i]++)next}1'
作者: bmne    时间: 2017-05-19 14:16
回复 37# elu_ligao


谢谢,谢谢。辛苦

大牛出手,招招带杀气

时间短的是我的1楼数据,时间长的是实战数据。另,时间长的估计不准,因为我同时在干别的事情中

1.jpg (22.15 KB, 下载次数: 23)

1.jpg

作者: me09    时间: 2017-05-25 17:27
回复 8# bmne

大概是用的列统计太多了 修改下:
  1. awk '!a[$1]++&&!b[$2]&&!c[$3]&&!d[$4]'
复制代码




作者: me09    时间: 2017-05-25 17:28
回复 8# bmne

大概是用的列统计太多了 修改下:
  1. awk '!a[$1]++&&!b[$2]&&!c[$3]&&!d[$4]'
复制代码




作者: me09    时间: 2017-05-25 17:28
回复 8# bmne

awk '!a[$1]++&&!b[$2]&&!c[$3]&&!d[$4]'
作者: me09    时间: 2017-05-25 17:58
回复 8# bmne

awk '!a[$1]++&&!b[$2]&&!c[$3]&&!d[$4]'
作者: me09    时间: 2017-05-28 07:21
本帖最后由 me09 于 2017-05-28 07:34 编辑

awk '{for(i=1;i<=NF;++i)if(a[$i]++)next; delete a}1' file  这个逻辑 和 awk '!a[$1]++&&!b[$2]++&&!c[$3]++&&!d[$4]++' 类似
作者: me09    时间: 2017-05-28 09:52
本帖最后由 me09 于 2017-05-28 11:54 编辑
elu_ligao 发表于 2017-05-19 11:23
编辑没用, 应该
awk '{delete a; for(i=1;i

这个看起来有点费劲:执行流程解释

1:delete a,释放 a;
2:for{i=1;i<=NF;i++} 行循环 具体到文本 就是  1 2 3 4的去遍历,i=1 对应域 $1,i=2 对应域 $2....:NF 是域数目,本行有4个域  NF=4
3:if(a[$i]++) next;这句是亮点,如果a[$i] ++为真 则next;跳过,也就是本行的遍历就此结束,不会走到最后的输出{ ...}1的部分
把脚本修改一个演示方式 就会比较容易理解:
awk '{delete a;for (i=1;i<=NF;i++) if(a[$i]++){print "next"}else{print "continue"}}1' c1
continue
continue
continue
continue
1 2 3 4
continue
continue
continue
continue
a b c d
continue
next
next
next
1 1 1 1
continue
next
continue
continue2 2 3 4
continue
continue
continue
continue
2 3 4 5


这么看就会比较容易理解这个判断的next;语句的用途, 只要行判断过程中出现一次next语句为真的输出,那么就会跳过这行,进入下一行的条件判断和执行,被跳过的行就不会有输出,因为执行不到{...}1的阶段,被next跳过了次行后续的执行动作。
4:{}1

awk ‘{code}1’ 中的“1”是干什么的?

一个完整的awk语句为:Awk ‘[patten]{action}……’, 其中pattern缺省为1,action缺省为{print}。

那么awk ‘1’完整的写法就是awk ‘1{print}’; 同理,awk ‘{print}’完整的写法也是awk ‘1{print}’。







作者: bmne    时间: 2017-05-28 10:08
回复 44# me09

谢谢,辛苦
一直关注你的帮助







欢迎光临 Chinaunix (http://bbs.chinaunix.net/) Powered by Discuz! X3.2