将列的前五个元素与其余元素进行比较

将列的前五个元素与其余元素进行比较

我希望你能帮助我解决这个问题。

我想将一列的前五个元素与其余元素进行比较(逐列)。

  • 如果前 5 个元素相等 --> 继续
  • 如果前 5 个元素相等且与其余元素不同,则打印这些列

该表有100多列和12行,表之间用TABS分隔。

输入示例:

约翰·劳拉·本·克里斯·丹·汤姆
约翰·劳拉·本·莱恩·丹·汤姆
约翰·劳拉·本·克里斯·丹·汤姆
约翰·劳拉·本·克里斯·丹·汤姆
约翰·劳拉·本·克里斯·丹·汤姆
戴夫·劳拉·泰勒克里斯·多纳·萨拉
戴夫·劳拉·哈维克里斯·丹·萨拉

期望的输出:

约翰·本·汤姆
约翰·本·汤姆
约翰·本·汤姆
约翰·本·汤姆
约翰·本·汤姆
戴夫·泰勒·萨拉
戴夫·哈维·萨拉

我非常感谢您的所有想法和评论,

谢谢

答案1

通常最好对行(行)进行操作。诸如awk一次只操作一行之类的工具。要将列转换为行(即转置),请使用GNUdatamash。然后awk可以分别对每一行进行适当的测试,打印或不打印。最后datamash再次使用将结果转置为原始格式:

<data datamash transpose | awk '{
    for (i=2; i<=5; i++) if ($1!=$i) next
    for (i=6; i<=NF; i++) if ($1==$i) next
    print
}' | datamash transpose

逻辑解释如下:

  • 如果 2..5 中的任何一个字段与字段号 1 不同,第一个for会跳过该行并重新开始。所有 5 个字段都相等是允许程序继续执行下一行代码的唯一可能性。
  • for如果以下任何字段与第一个字段相同,第二个字段将跳过该行并重新开始。
  • 如果程序超出了这两个for标准,则意味着根本没有发现与您的标准相矛盾的情况。只有这样才能打印整行。

笔记:

  • 在原始问题(无需转置)中,仅当至少有一列尚未与您的标准相矛盾时,您才需要阅读下一行。根据数据的不同,在读取前几行后,所有列都可能被声明为不匹配。在这种情况下,算法可以快速退出并且什么也不打印。但datamash transpose无论数据如何,都需要读取和处理整个文件(或流)。在这种情况下,我的解决方案并不理想。
  • 万一不可datamash用,有一个awk解决方案这里

答案2

我们需要将列转置为行,然后运行正则表达式检查要打印的行。那些具有相同前五个元素的元素不应在下面再次看到相同的元素。最后重新转置结果以获得所需的输出。

HTH。

rs -T  inp |
perl -lane 'print if "@F" =~ /^(\S+)(?: \1){4}(?: (?:(?!\1(?=(?: |$))).)+)+$/' |
rs -T

输出:

Jhon    Ben     Tom
Jhon    Ben     Tom
Jhon    Ben     Tom
Jhon    Ben     Tom
Jhon    Ben     Tom
Dave    Taylor  Sara
Dave    Harvey  Sara

相关内容