You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何更高效搜索JavaScript对象以匹配颜色名称或别名?

问题描述

我想要通过颜色的通用名称或别名来匹配颜色。目前的实现是把colorMap拆成16个独立数组,再逐个遍历查找匹配项,代码如下:

if (colorMap) {
    for (const [key, value] of Object.entries(colorMap)) {
        // colorMap broken down into arrays
        let values = Object.values(value)
        // If the color name is in the array
        if (values[0].includes(swatch.color)) {
            // add it to the swatch object
            swatch.generic.push(key)
            break;
        }
    }
}

colorMap的结构为:一个对象,每个键是颜色通用名(如"Red"),对应的值是包含数组的对象,数组内存放该通用名下的所有颜色别名(如["Crimson", "Scarlet"])。

但这个方案速度很慢,且偶尔失效,当存在数百个swatch.color时会直接超时。有没有更高效的搜索方式?

参考完整代码:

import { useMemo } from 'preact/hooks'

export const useSwatches = ({
    variantColors,
    colorMap,
    variantImages,
    swatchImages,
    fallbackImage,
}) => {
    return useMemo(() => {
        if (!variantColors || !swatchImages || !variantImages) {
            return []
        } else {
            let swatchList = new Set();
            let swatches = JSON.parse(swatchImages)
            let images = JSON.parse(variantImages)
            let colorMap = JSON.parse(window.Resources.colorMap.textContent)
               

            variantColors.forEach(function (color, index) {
                let swatch = new Object();

                swatch.color = color.replaceAll('  ', ' ');

                swatch.generic = []

                swatch.fallback_img = fallbackImage;

                images.forEach(function (img, index) {
                    if (img.color == swatch.color) {
                        swatch.thumbnail = img.img;
                    }
                })

                if (!swatch.thumbnail) {
                    swatch.thumbnail = fallbackImage
                }

                swatches.forEach(function (img, index) {
                    let splitImg = img.split('/');
                    let swatchMatcher = splitImg[splitImg.length-1];

                    if (swatchMatcher.split('.')[0] === (swatch.color.replaceAll(' ', '-').toLowerCase())) {
                        swatch.swatch_image = img
                    }
                })

                if (!swatch.swatch_image) {
                    swatch.swatch_image = fallbackImage
                }

                if (colorMap) {    
                    for (const [key, value] of Object.entries(colorMap)) {
                        // colorMap broken down into arrays
                        let values = Object.values(value)
                        // If the color name is in the array
                        if (values[0].includes(swatch.color)) {
                            // add it to the swatch object
                            swatch.generic.push(key)
                            break;
                        }
                    }
                }

                swatchList.add(swatch);
            });

            return swatchList;
        }
    }, [
        variantColors,
        colorMap,
        variantImages,
        swatchImages,
        fallbackImage,
    ])
}
优化方案

核心思路是预构建反向映射表,将所有颜色别名直接映射到对应的通用名,把原来的O(n)遍历查找改成O(1)的对象属性访问,彻底解决超时问题。

步骤1:预处理colorMap生成反向映射

在useMemo内部提前构建别名到通用名的映射表,仅在依赖变化时重新生成:

const aliasToGeneric = useMemo(() => {
    if (!window.Resources?.colorMap?.textContent) return {};
    const parsedColorMap = JSON.parse(window.Resources.colorMap.textContent);
    const map = {};
    for (const [genericName, entry] of Object.entries(parsedColorMap)) {
        const aliases = Object.values(entry)[0];
        aliases.forEach(alias => {
            map[alias] = genericName;
        });
    }
    return map;
}, [colorMap]);

步骤2:替换原遍历查找逻辑

把原来嵌套的遍历代码直接替换为:

if (aliasToGeneric[swatch.color]) {
    swatch.generic.push(aliasToGeneric[swatch.color]);
}

额外优化:图片查找逻辑的性能提升

原代码中两处图片查找的forEach遍历也可以用同样的思路优化:

  1. 预构建颜色到缩略图的映射:
const colorToThumbnail = useMemo(() => {
    if (!variantImages) return {};
    const parsedImages = JSON.parse(variantImages);
    const map = {};
    parsedImages.forEach(img => {
        map[img.color] = img.img;
    });
    return map;
}, [variantImages]);

替换原图片查找:

swatch.thumbnail = colorToThumbnail[swatch.color] || fallbackImage;
  1. 预构建颜色到样本图的映射:
const colorToSwatchImage = useMemo(() => {
    if (!swatchImages) return {};
    const parsedSwatches = JSON.parse(swatchImages);
    const map = {};
    parsedSwatches.forEach(img => {
        const splitImg = img.split('/');
        const swatchName = splitImg[splitImg.length - 1].split('.')[0];
        // 转换格式,和swatch.color的处理逻辑保持一致
        const colorKey = swatchName.replaceAll('-', ' ');
        map[colorKey] = img;
    });
    return map;
}, [swatchImages]);

替换原样本图查找:

swatch.swatch_image = colorToSwatchImage[swatch.color] || fallbackImage;

完整优化后的代码

import { useMemo } from 'preact/hooks'

export const useSwatches = ({
    variantColors,
    colorMap,
    variantImages,
    swatchImages,
    fallbackImage,
}) => {
    // 预构建所有映射表,仅在依赖变化时重新生成
    const aliasToGeneric = useMemo(() => {
        if (!window.Resources?.colorMap?.textContent) return {};
        const parsedColorMap = JSON.parse(window.Resources.colorMap.textContent);
        const map = {};
        for (const [genericName, entry] of Object.entries(parsedColorMap)) {
            const aliases = Object.values(entry)[0];
            aliases.forEach(alias => {
                map[alias] = genericName;
            });
        }
        return map;
    }, [colorMap]);

    const colorToThumbnail = useMemo(() => {
        if (!variantImages) return {};
        const parsedImages = JSON.parse(variantImages);
        const map = {};
        parsedImages.forEach(img => {
            map[img.color] = img.img;
        });
        return map;
    }, [variantImages]);

    const colorToSwatchImage = useMemo(() => {
        if (!swatchImages) return {};
        const parsedSwatches = JSON.parse(swatchImages);
        const map = {};
        parsedSwatches.forEach(img => {
            const splitImg = img.split('/');
            const swatchName = splitImg[splitImg.length - 1].split('.')[0];
            const colorKey = swatchName.replaceAll('-', ' ');
            map[colorKey] = img;
        });
        return map;
    }, [swatchImages]);

    return useMemo(() => {
        if (!variantColors || !swatchImages || !variantImages) {
            return [];
        }

        const swatchList = new Set();

        variantColors.forEach(color => {
            const swatchColor = color.replaceAll('  ', ' ');
            const swatch = {
                color: swatchColor,
                generic: [],
                fallback_img: fallbackImage,
                thumbnail: colorToThumbnail[swatchColor] || fallbackImage,
                swatch_image: colorToSwatchImage[swatchColor] || fallbackImage
            };

            // 匹配通用颜色名
            if (aliasToGeneric[swatchColor]) {
                swatch.generic.push(aliasToGeneric[swatchColor]);
            }

            swatchList.add(swatch);
        });

        return swatchList;
    }, [
        variantColors,
        aliasToGeneric,
        colorToThumbnail,
        colorToSwatchImage,
        fallbackImage,
    ]);
}

优化说明

  • 所有映射表通过useMemo缓存,避免重复计算
  • 将O(n)遍历查找全部改为O(1)的对象属性访问,数据量越大性能提升越明显
  • 代码结构更简洁,减少嵌套逻辑

内容的提问来源于stack exchange,提问作者Tom Hanks

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.06 00:40:18