JavaScript:在两个对象数组中查找匹配项和差异

时间:2020-06-01 15:59:02

标签: javascript node.js json

好的,所以这很困难。我想。

我有两个对象数组,其中包含有关Pod的一些信息。我希望提供环境的并排比较,以显示吊舱中包含完全相同的图像;诀窍在于,我需要捕捉图像不匹配的豆荚。结果将呈现在一个看起来像这样的表上(至少是第一次迭代):

|---------------------|------------------|------------------|
|      Pod Name       | Image from Env1  |  Image from Env2 |
|---------------------|------------------|------------------|
|          foo        |     foo:1.0.0    |     foo:1.0.0    |   <---- images match
|---------------------|------------------|------------------| 
|          foo        |   foobar:1.0.0   |                  |   <---- No match for image tag; image name different from the pod name as the pods may contain multiple images
|---------------------|------------------|------------------| 
|          foo        |                  |    foobar:2.0.0  |   <---- As above
|---------------------|------------------|------------------|
|          bar        |     bar:2.0.0    |     bar:2.0.0    |   <---- images match 
|---------------------|------------------|------------------|
|          baz        |     baz:1.0.0    |                  |   <----
|---------------------|------------------|------------------|         Note the 'no match'; so own row for now
|          baz        |                  |     baz:2.0.0    |   <----
|---------------------|------------------|------------------|

稍后我将使用CSS突出显示匹配与差异。

我最努力的事情是:

  • 广告连播可能包含1张以上的图片。这些图像之一可能在环境之间匹配,而另一个可能不匹配。如果有一张以上的图片,则该窗格中的标签会有所不同(请参见上表中的foo窗格)
  • 如何在环境之间检查对象是否匹配,同时仍捕获不匹配的对象。使用嵌套循环会导致一堆重复和误报的问题
  • 我不确定存储输出的最佳方法。可能类似于:[{ "Pod Name": "foo", "Image_Env_1": foo:1.0.0", "Image_Env_2": foo:1.0.0"}...,并在不匹配的情况下为值保留空白字符串(如表中的空白单元格)。但这可能会与foo窗格中具有其他图像标签的其他图像发生冲突。

因此Env1数组类似于以下代码片段:

[
    {
        "Image": {
            "S": "foo:1.0.0"
        },
        "Pod Name": {
            "S": "foo"
        }
    },
    {
        "Image": {
            "S": "foobar:0.2.0"
        },
        "Pod Name": {
            "S": "foo"
        }
    },
    {
        "Image": {
            "S": "bar:1.0.0"
        },
        "Pod Name": {
            "S": "bar"
        }
    },
    {
        "Image": {
            "S": "baz:1.0.0"
        },
        "Pod Name": {
            "S": "baz"
        }
    },
    {
        "Image": {
            "S": "qux:1.0.0"
        },
        "Pod Name": {
            "S": "foo"
        }
    }
]

Env2数组:

[
    {
        "Image": {
            "S": "foo:2.0.0"
        },
        "Pod Name": {
            "S": "foo"
        }
    },
    {
        "Image": {
            "S": "foobar:0.2.0"
        },
        "Pod Name": {
            "S": "foo"
        }
    },
    {
        "Image": {
            "S": "bar:1.0.0"
        },
        "Pod Name": {
            "S": "bar"
        }
    },
    {
        "Image": {
            "S": "baz:3.0.0"
        },
        "Pod Name": {
            "S": "baz"
        }
    }
]

2 个答案:

答案 0 :(得分:0)

您可以编写一个小助手方法,该方法汇总来自您的环境文件的信息,即首先按pod分组,然后汇总使用的图像。这样,在多个环境中使用图像的过滤条目就不那么重要了。

类似的东西(请注意,这适用于任意数量的环境)

function getAggregatedPodInfos(...environments) {
    const aggregatedInfos = {pods: {}, environments: []};
    environments.forEach(env => addEnvironmentInfos(env, aggregatedInfos))
    return aggregatedInfos;
}

function addImageInfoByEnvironment(pod, environment, imageName) {
    if (!pod.imageInfo[environment.envName]) {
        pod.imageInfo[environment.envName] = [];
    }
    pod.imageInfo[environment.envName].push(imageName)
}

function addEnvironmentInfos(environment, envInfo) {
    envInfo.environments.push(environment.envName);
    for (const envEntry of environment.data) {
        const podName = envEntry["Pod Name"]["S"];
        const imageName = envEntry["Image"]["S"];
        if (!envInfo.pods[podName]) {
            envInfo.pods[podName] = {imageInfo: {}};
        }
        addImageInfoByEnvironment(envInfo.pods[podName], environment, imageName);
    }
}

const res = getAggregatedPodInfos({envName: 'env1', data: env1}, {envName: 'env2', data: env2});
console.log(JSON.stringify(res))

这将打印:

{
    "pods": {
        "foo": {
            "imageInfo": {
                "env1": ["foo:1.0.0", "foobar:0.2.0", "qux:1.0.0"],
                "env2": ["foo:2.0.0", "foobar:0.2.0"]
            }
        },
        "bar": {
            "imageInfo": {
                "env1": ["bar:1.0.0"],
                "env2": ["bar:1.0.0"]
            }
        },
        "baz": {
            "imageInfo": {
                "env1": ["baz:1.0.0"],
                "env2": ["baz:3.0.0"]
            }
        }
    },
    "environments": ["env1", "env2"]
}

答案 1 :(得分:0)

这很难!但是我认为该过程可以分为两个主要阶段:

  1. 找到匹配项和差异项。
  2. 将这些信息转换为有用的东西。

第一步可以进一步分解为处理原始数据,然后对其进行处理。

在处理诸如Pod Name之类的类别时,我想做的是创建包含Set对象的Map对象。在这种情况下,它可能看起来像这样:

// Let's assume Env1 is loaded already.
const podNameMap1 = new Map();
Env1.forEach( (value, index) => {
    // Here 'value' is element in Env1

    const podName = value['Pod Name'].S;
    const podValue = podNameMap.get(podName);
    // returns undefined if it does not exist

    if (!podValue) {
        podNameMap.set(podName, new Set(value['Image'].S) );
        // If there is no podValue, set podName to a new Set with the images in it.
    } else {
        // Here there is a podValue, and we can add a new member to the Set.
        podValue.add(value['Images'].S);
        // podValue is a Set object which means the map value needs to be set one time.
    }
});

podNameMap1的末尾包含所有吊舱及其所有图像。下一步是对Env2做同样的事情,这时有两个地图,显示了各种容器名称和图像。

之后,可以进行比较,这比创建地图要复杂得多:

// Let's assume podNameMap1 and podNameMap2 are both loaded.
// I don't know if it's possible for pods to be mismatched,
// I'm going to assume they are cannot be.

// Images in both
const inBothEnvsMap = new Map();
// Images in env1 but not env2
const inEnv1Map = new Map();
// Images in env2 but not env1
const inEnv2Map = new Map();

podNameMap1.forEach( (imageSet1, podName) => {
    // Here, imageSet1 and podName are self explanitory
    const imageSet2 = podNameMap1.get(podName); // assuming this is always the case

    // Computing the set intersections n stuff
    const inEnv1 = new Set();
    const inEnv2 = new Set();
    const inBothEnvs = new Set();

    // Note: I wish JS had built in set operations because there's probably
    // a better way to do this but alas...
    imageSet1.forEach( image => {
        if (imageSet2.has(image))
            inBothEnvs.add(image);
        else // in imageSet1 only
            inEnv1.add(image);
    });
    // now inEnv1 AND inBothEnvs are complete

    imageSet2.forEach( image => {
        if (!imageSet1.has(image))
            inEnv2.add(image);
    });

    // now this pod is done
    inBothEnvsMap.set(podName, inBothEnvs);
    inEnv1Map.set(podName, inEnv1);
    inEnv2Map.set(podname, inEnv2);
});

此时,这是“查找匹配和差异”步骤。

继续进行下一步“将信息转换为有用的东西”的部分不是简单的设置操作所特有的,因此我无法真正给出合理的建议。