首页 > 解决方案 > 基于现有对象数组中的一个属性的新数组

问题描述

我试图找出在 NodeJS 中使用字符串相似性库和我的项目中使用的 2 个数组的最干净的方法。

第一个是一个对象数组,看起来像这样:

{
    eventName: "Some event name",
    tournamentName: "US Open",
    city: "New York"
}

第二个数组包含看起来略有不同的对象,例如:

{
    eventName: "Some event name",
    temperature: "28",
    spectators: "15000"
}

我正在尝试做的是构建一些迭代第一个数组并在第二个数组中找到最匹配的事件名称的东西,当然仅基于使用“字符串相似性”NodeJS 库的 eventName 属性。

下面的方法效果很好:

stringSimilarity.findBestMatch(eventName, arrayOfEventNames)

但当然,第二个参数需要一个仅包含事件名称的数组。我没有那个。我有一个由对象组成的数组。确实,这些对象的属性之一是事件名称,所以我试图找出将其传递给此函数的最佳方法。我构建了下面的函数(在第一个数组的 forEach 中调用它),它基本上接受我要搜索的事件的名称和第二个对象数组,然后在其中创建一个新的临时数组,其中只有事件名称。然后我有 2 个输入,我需要调用 stringSimilarity.findBestMatch 方法。

function findIndexOfMatchingEvent(eventName, arrayToCompareAgainst) {
    let onlyEventNames = [];
    
    arrayToCompareAgainst.forEach(e => {
        onlyEventNames.push(e.eventName);
    });
    
    if (arrayToCompareAgainst.length !== onlyEventNames.length) {
        throw new Error("List of events array length doesn't match event names array length!");
    }
    
    const bestMatch = stringSimilarity.findBestMatch(eventName, onlyEventNames);
    const bestMatchEventName = bestMatch.bestMatch.target;
    const bestMatchAccuracyRating = bestMatch.bestMatch.rating;

    const index = arrayToCompareAgainst.findIndex(e => {
        return e.eventName === bestMatchEventName;
    });

    if (index === -1) {
        throw new Error("Could not find matched event in original event list array");
    } else if (bestMatchAccuracyRating >= 0.40) {
        return index;
    }
}

这行得通,但对我来说感觉很不对。我多次创建这个新的临时数组。如果我的第一个数组有 200 个对象,那么对于每个对象,我都会调用我的自定义函数,然后创建这个临时数组 (onlyEventNames) 200 次。更糟糕的是,它并没有以任何方式真正连接到原始数组,这就是为什么我然后使用 .findIndex 返回并查找找到的事件所指的数组中的哪个对象。

非常感谢对此提供一些反馈/建议。提前致谢!

标签: javascriptnode.jsarrayssimilarity

解决方案


在我之前的回答中,我误解了这个问题。

无需为要比较的另一个数组中的每个条目重新创建事件名称数组。一次创建事件名称数组,然后在遍历另一个数组的条目时重用该数组。您可以像在 中那样创建事件名称数组findIndexOfMatchingEvent,但更惯用的方式是使用map.

假设这些数组:

const firstArray = [
    {
        eventName: "Some event name",
        tournamentName: "US Open",
        city: "New York"
    },
    // ...
];
const secondArray = [
    {
        eventName: "Some event name",
        temperature: "28",
        spectators: "15000"
    },
    // ...
];

然后你可以这样做:

const onlyEventNames = secondArray.map(e => e.eventName);
let bestResult;
let bestRating = 0;
for (const {eventName} of firstArray) {
    const result = stringSimilarity.findBestMatch(eventName, onlyEventNames)
    if (!bestResult || bestRating < result.rating) {
        // Better match
        bestResult = secondArray[result.bestMatchIndex];
        bestRating = result.rating;
    }
}
if (bestRating >= 0.4) {
    // Use `bestResult`
}

完成循环后,bestResult将是第二个数组中与第一个数组中的事件最匹配的对象,并且bestRating将是该对象的评分。(假设数组中有条目。如果没有条目firstArraybestResult将是undefined并且bestRating将是0;如果第二个数组中没有任何条目,我不知道findBestMatch返回什么[或者它是否抛出]。)

关于您的具体问题:

我多次创建这个新的临时数组。

是的,这绝对不是理想的(尽管有 200 个元素,这真的不是什么大问题)。这就是为什么在上面我只创建一次并重用它。

...它并没有以任何方式真正连接到原始阵列...

它是:按索引。您肯定知道,如果在 的索引 2 处找到匹配项onlyEventNames,则该匹配项是针对 的索引 2 的secondArray。在上面的代码中,我使用findBestMatch.


推荐阅读