在一个“键 - 值列表”文件中查找包含未映射到第二个“键值”文件中的该键的数据字段的行

在一个“键 - 值列表”文件中查找包含未映射到第二个“键值”文件中的该键的数据字段的行

我有2个文件。一个文件每行至少包含两个字段(用户名、年龄和各自字段中的可变数量的“水果”),另一个文件每行始终包含两个字段(用户名和一个“水果”) 。我将称之为file1“数据库”文件和file2“映射”文件。

对于每个用户名,我想检查与该用户对应的任何行是否file1包含“水果”不是根据 映射到该用户file2

例子:

  • file1(此文件中每行的水果数量是可变的):

    james,25,strawberry,rassberry,blueberry
    james,25,strawberry,rassberry,mango
    james,26,blueberry
    james,27,pineapple
    erik,30,strawberry,rassberry,mango
    
  • file2

    james,strawberry
    james,rassberry
    james,blueberry
    erik,blueberry
    erik,rassberry
    
  • 期望的输出:

    james,25,strawberry,rassberry,mango
    james,27,pineapple
    erik,30,strawberry,rassberry,mango
    

    选择这些行是因为不包含 user或与 userfile2的关联,也不包含user和与user 的关联。mangopineapplejamesstrawberrymangoerik

我只能用我的代码得到部分解决方案。我在下面尝试过,但这并没有检查同一行中的其他列。

awk 'BEGIN{FS=OFS=","}NR==FNR{a[$1]=$2;next}
{if (a[$1] && (a[$1]!=$3)){print $0, a[$1]}}' file2 file1

答案1

awk -F, '
    !nxtfile{ join[$1]= (join[$1]==""?"": join[$1] FS) $2; next }
            { split(join[$1], tmp, ","); for(x in tmp) fruits[tmp[x]];
              for(i=3; i<=NF; i++) if(!($i in fruits)) { print; break }
            }
' file2 nxtfile=1 file1

在第一个块中,我们正在处理输入文件2并将不同行中的所有水果连接在一起以获得相同的结果姓名并将它们作为键/值对存储到名为的关联数组中加入

在第二个块中,我们正在处理输入文件1并从数组中获取匹配的第一个字段的值,并将其以逗号分隔符拆分为临时数组tmp,然后我们重建另一个数组水果与价值观tmp数组用作键水果数组(换句话说,我们正在交换tmp数组的值成为水果大批)。

那么最后一步是循环 >=3 rd字段到最后并逐一检查该字段是否存在于水果数组,在第一个不匹配的字段上,我们打印整行并中断循环,因为不需要继续读取其余字段。

答案2

当然比公认的 awk 解决方案行数更多,但如果您不了解 awk(像我一样),可能会更清楚。

这使用了 Python 的集合,它允许我们清楚地询问,“这个水果列表是否有一个不在查找/引用列表中的元素(水果)?”:

import csv
import sys
from collections import defaultdict

# Will look something like { james: [strawberry, ...], erik: [blue, ...] }
lookup = defaultdict(set)

with open('file2', newline='') as f:
    reader = csv.reader(f)

    for row in reader:
        name, fruit = row
        lookup[name].add(fruit)


writer = csv.writer(sys.stdout)

with open('file1', newline='') as f:
    reader = csv.reader(f)

    for row in reader:
        name = row[0]
        these_fruits = set([x for x in row[2:] if x])

        # see my note below on how set.difference(set) works
        if not these_fruits.difference(lookup[name]):
            # no difference
            continue

        writer.writerow(row)

工作原理如下set.difference(set)

>>> {1,2}.difference({1,2,3})
set()
>>> {1,2,3}.difference({1,2,3})
set()
>>> {1,2,4}.difference({1,2,3})
{4}

直到左侧有一个元素而右侧没有时,才会出现差异。

相关内容