基于现有对象数组中的一个 属性 的新数组

New array based on one property in existing object array

我正在尝试找出将 NodeJS 中的字符串相似性库与我的项目中使用的 2 个数组一起使用的最简洁方法。

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

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

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

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

我想做的是构建一些东西来遍历第一个数组并在第二个数组中找到最接近的匹配事件名称,当然仅基于事件名称 属性 使用“字符串-相似性”NodeJS 库。

下面的方法非常有效:

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 返回并查找 found 事件引用的数组中的哪个对象。

真的很感激 feedback/advice 在这方面。提前致谢!

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

无需为要比较的另一个数组中的每个条目重新创建事件名称数组。创建事件名称数组一次,然后在循环遍历另一个数组的条目时重用该数组。您可以像在 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 将是该对象的评级. (假设数组中有条目。如果 firstArray 中没有条目,bestResult 将是 undefinedbestRating 将是 0;如果有第二个数组中没有任何内容,我不知道 findBestMatch returns [或者它是否抛出]。)

关于您的具体问题:

I'm creating this new temporary array so many times.

是的,这绝对不理想(虽然有 200 个元素,但确实不是什么大问题)。这就是为什么在上面我只创建一次并重复使用它。

...it's not really connected to the original array in any way...

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

返回的索引获取条目