【问题标题】:find difference between old and new mapping for each clientId查找每个 clientId 的新旧映射之间的差异
【发布时间】:2018-10-12 03:11:43
【问题描述】:

我有如下所示的映射文件:

new_primary_mapping.txt

{1=[343, 0, 686, 1372, 882, 196], 2=[687, 1, 1373, 883, 197, 736, 1030, 1569], 3=[1374, 2, 884, 737, 198, 1570]}

new_secondary_mapping.txt

{1=[1152, 816, 1488, 336, 1008], 2=[1153, 0, 817, 337, 1489, 1009, 1297], 3=[1, 1154, 1490, 338]}

在上述映射文件中,每个clientId 都有新的主映射和新的辅助映射。例如:clientId 1 具有 343, 0, 686, 1372, 882, 196 新的主映射和 1152, 816, 1488, 336, 1008 新的辅助映射。其他clientIds 也是如此。下面是我的脚本,它为每个 clientId 打印数组:

#!/bin/bash
mapfiles=(new_primary_mapping.txt new_secondary_mapping.txt)

declare -a arr

mappingsByClientID () {
  id=$1 # 1 to 5 
  file=${mapfiles[$2]} # 0 to 1
  arr=($(sed -r "s/.*\b${id}=\[([^]\]+).*/\1/; s/,/ /g" $file))
  echo "${arr[@]}"
}

# assign output of function to an array
# and get mapping for clientId 3
pri=($(mappingsByClientID 3 0))
snd=($(mappingsByClientID 3 1))

# print whole array
echo "whole arr pri: ${pri[@]}"
echo "whole arr snd: ${snd[@]}"

现在我有另外两个文件,如下所示,它们具有相同 clientId's 的旧映射。

old_primary_mapping.txt

{1=[686, 1372, 882, 196], 2=[883, 197, 736, 1030, 1569], 3=[1374, 2, 884, 737]}

old_secondary_mapping.txt

{1=[1488, 336, 1008], 2=[817, 337, 1489, 1009, 1297], 3=[1490, 338]}

问题陈述

现在我需要阅读所有四个文件,对于每个clientId,我需要找出新映射和旧映射之间不常见的地方(含义差异)。

例如:clientId 1 具有 343, 0, 686, 1372, 882, 196 新的主映射和 1152, 816, 1488, 336, 1008 新的辅助映射。 还有clientId 1686, 1372, 882, 196 旧的主映射和1488, 336, 1008 旧的辅助映射。

所以我将创建一个包含以下条目的 pri 数组:343 0 和将包含以下条目的 sec 数组:1152 816。因为这些是每个 clientId 的新旧映射之间的区别。我怎样才能在 shell 脚本中做到这一点?这可以吗?

此外,如果没有区别,则只需创建一个空数组并记录一条消息。

更新:

对于clientId 1,它应该打印:

pri=(343 0)
snd=(1152 816)

对于clientId 2

pri=(687 1 1373)
snd=(1153 0)

对于clientId 3

pri=(198 1570)
snd=(1 1154)

注意:只要数字相同,就可以匹配。数字的顺序无关紧要。所以我需要找到每个 clientId 不常见的那些数字。

这是我删除文件的方式,但是当我运行它时,它给了我错误:

for dir_name, numbers in (('primary', pri), ('secondary', snd)):
    for number in numbers:
        for filename in glob.glob('/{}/proc_{}_for_*.log'.format(dir_name, number)):
             os.unlink(filename)

这是我得到的错误:

NameError: name 'pri' is not defined

【问题讨论】:

  • 问题:1) 你能认为数组一直在增长吗?这是否意味着新数组中的信息会比旧数组中的更多? 2) 数组总是以新旧相同的顺序生成吗?
  • 新数组的大小将始终小于每个 clientId 的旧数组。在示例中,我有相反的情况。只是想在示例中说明清楚,所以我想出了这个。没有按照你的第二个问题回答?
  • 示例old_primary 1=[686, 1372, 882, 196]new_primary 1=[343, 0, 196, 882, 1372, 686]
  • @Allan 它可以是任何顺序。我猜一定有办法找到两个数组之间的差异?
  • @RomanPerekhrest 为什么你不认为这是一个区别? new_primary1=[343, 0, 686, 1372, 882, 196]old_primary1=[686, 1372, 882, 196]。这里的区别只是 343 0 对主要的,因为其他数字是匹配的?

标签: python linux bash shell sed


【解决方案1】:

标准命令

使用标准 unix 命令排序和通信的简短解决方案

new_primary=(343 0 686 1372 882 196)
old_primary=(686 1372 882 196)
comm -23 <( printf "%s\n" "${new_primary[@]}" | sort ) <( printf "%s\n" "${old_primary[@]}" | sort )

comm 接收两个文件(必须按字典顺序排序)并生成带有分隔符 &lt;tab&gt; 的 3 列输出

  • 第一列“仅在第一个文件中”
  • 第二列“仅在第二个文件中”
  • 第三列“两者”

选项-1-2-3正在删除相应的列,所以-23只保留在第一列。

如果必须经常调用此操作,启动许多进程可能会很长,在这种情况下,只能使用 bash 内置函数和函数来完成:

bash 4

arr_to_set() {
    declare -n arr_name=$1
    local set_name=$2 e
    declare -gA "$set_name=()"
    for e in "${arr_name[@]}"; do
        declare -g $set_name[$e]=1
    done
}

comm_set() {
    declare -n set1_=$1 set2_=$2
    declare -gA "comm_only1=()" "comm_only2=()" "comm_both=()"
    for k in "${!set1_[@]}"; do
        if [[ -z ${set2_[$k]} ]]; then
            comm_only1[$k]=1
        else
            comm_both[$k]=1
        fi
    done
    for k in "${!set2_[@]}"; do
        if [[ -z ${set1_[$k]} ]]; then
            comm_only2[$k]=1
        fi
    done
}

new_primary=(343 0 686 1372 882 196)
old_primary=(686 1372 882 196)
arr_to_set new_primary new_primary_set
arr_to_set old_primary old_primary_set
comm_set new_primary_set old_primary_set
typeset -p comm_only1
printf "%8s\n" "${!comm_only1[@]}"

【讨论】:

  • 感谢您的建议。我怎样才能将它与我的脚本集成并同时使用旧的和新的辅助映射?
【解决方案2】:

Python解决方案:

diff_mappings.py脚本:

import sys, re, json

with open(sys.argv[1]) as old_primary, open(sys.argv[2]) as new_primary, \
    open(sys.argv[3]) as old_second, open(sys.argv[4]) as new_second:

    prepare_json = lambda f: json.loads(re.sub(r'([0-9]+)=', '"\\1":', f.read())) 
    old_pr_data = prepare_json(old_primary)
    new_pr_data = prepare_json(new_primary)
    old_snd_data = prepare_json(old_second)
    new_snd_data = prepare_json(new_second)

    for k in sorted(old_pr_data):
        print('ClientId ' + k)
        print('pri=({})'.format(' '.join(map(str, set(old_pr_data[k]) ^ set(new_pr_data[k])))))
        print('snd=({})\n'.format(' '.join(map(str, set(old_snd_data[k]) ^ set(new_snd_data[k])))))

用法(输入文件的顺序很重要,但该方法也可以重新排列以直接在脚本中按名称访问文件):

python diff_mappings.py old_primary_mapping.txt new_primary_mapping.txt old_secondary_mapping.txt new_secondary_mapping.txt

输出:

ClientId 1
pri=(0 343)
snd=(1152 816)

ClientId 2
pri=(1 687 1373)
snd=(0 1153)

ClientId 3
pri=(198 1570)
snd=(1 1154)

【讨论】:

  • aah 这非常紧凑。不错.. 还有什么方法可以打印prisnd 数组,仅用于传递给此脚本的clientId,而不是打印所有内容?假设我通过clientId 3 那么它应该只为那个clientId打印prisnd数组?或者我可以多取一个参数并在 for 循环中检查 k 并相应地打印。
  • 当然,而不是 for 循环,如果事先知道键值,您可以直接访问所需的键,例如k = '3'; print('ClientId ' + k); print('pri=({})'.format(' '.join(map(str, set(old_pr_data[k]) ^ set(new_pr_data[k])))))
  • aah 我明白了.. 有道理.. 让我测试一下,看看它看起来如何.. 我只是在阅读它,我也可以使用 python 删除文件,所以我将修改这个脚本也能做到这一点。
  • 我也在想,我们可以将 pri 和 snd 作为一个合适的数组吗?因为我需要迭代它们来删除文件。我已经更新了我的问题,我在其中添加了我是如何做的,但是在当前的实现中它由于某种原因不起作用。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2015-03-19
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-09-29
  • 2014-02-02
  • 2012-02-09
相关资源
最近更新 更多