如何比较仅包含2个参数的函数中的多个值?

时间:2017-11-09 10:27:24

标签: javascript algorithm

我正在尝试构建一个十六进制颜色比较器,它比较数组中的值并删除相似的颜色,保持颜色与像素最多。

以下是输入的示例,数组的长度可以从1更改为更多:

[…]
0: Array [ "ffffff", 12992 ]
1: Array [ "da542f", 3117 ] #similar
2: Array [ "da5630", 60 ]   #similar
length: 3

(index: Array [hexColor, NumberOfPixel])

输出如下所示:

[…]
0: Array [ "ffffff", 12992 ]
1: Array [ "da542f", 3117 ]
length: 2

我想出了什么,因为以下示例是超级硬编码并产生错误我希望避免在彼此内部使用多个if / else,hexColorCalc()函数来自此 {{ 3}}

post

// ordered by highest pixel
colors_lst = [
  ["333333", 6421], 
  ["da542f", 3117],
  ["da5630", 60]
]

console.log(colors_lst);

function hexColorDelta(array) {
  function hexColorCalc(hex1, hex2) {
    // get red/green/blue int values of hex1
    var r1 = parseInt(hex1.substring(0, 2), 16);
    var g1 = parseInt(hex1.substring(2, 4), 16);
    var b1 = parseInt(hex1.substring(4, 6), 16);
    // get red/green/blue int values of hex2
    var r2 = parseInt(hex2.substring(0, 2), 16);
    var g2 = parseInt(hex2.substring(2, 4), 16);
    var b2 = parseInt(hex2.substring(4, 6), 16);
    // calculate differences between reds, greens and blues
    var r = 255 - Math.abs(r1 - r2);
    var g = 255 - Math.abs(g1 - g2);
    var b = 255 - Math.abs(b1 - b2);
    // limit differences between 0 and 1
    r /= 255;
    g /= 255;
    b /= 255;
    // 0 means opposit colors, 1 means same colors
    return (r + g + b) / 3;
  }

  // Do nothing since nothing to compare
  if (array.length == 1) {
    console.log('length of array : 1');
    return array
  }

  // Just compare both values and erase the one with least pixel
  if (array.length == 2) {
    console.log('length of array : 2');
    var hex1 = array[0][0];
    var hex2 = array[1][0];


    if (hexColorCalc(hex1, hex2) > 0.9) {
      colors_lst = array.pop(); // Get ride of last item in array
      return colors_lst;
    }
  }

  // Problems 
  if (array.length == 3) {
    var hex1 = array[0][0];
    var hex2 = array[1][0];
    var hex3 = array[2][0];

    // if True, other if/else below won't be working
    if (hexColorCalc(hex1, hex2) > 0.9) {
      array.splice(2, 1);
    }

    if (hexColorCalc(hex1, hex3) > 0.9) {
      array.splice(3, 1);
    }

    if (hexColorCalc(hex2, hex3) > 0.9) {
      array.splice(2, 1);
    }

    return array
  }
}

console.log(hexColorDelta(colors_lst));

我评论了代码是如何工作的,我在理解这个问题的正确算法时遇到了一些麻烦。如何避免硬编码并返回没有相似之处的正确列表?

2 个答案:

答案 0 :(得分:1)

为避免过度使用if,尤其是对于组合会爆炸的大型阵列,您可以依赖循环。以下是我对您的代码进行一些清理后提出的解决方案:

// splits the hex value to its components
function splitHex(hex) {
    return {
        r: parseInt(hex.substring(0, 2), 16),
        g: parseInt(hex.substring(2, 4), 16),
        b: parseInt(hex.substring(4, 6), 16)
    };
}

// return number between 0 (opposit colors) and 1 (same colors)
function hexColorCalc(hex1, hex2) {
    // get red/green/blue int values of hex1
    const hex1Split = splitHex(hex1);
    // get red/green/blue int values of hex2
    const hex2Split = splitHex(hex2);
    // calculate normalized differences between reds, greens and blues
    const r = 1 - Math.abs(hex1Split.r - hex2Split.r) / 255;
    const g = 1 - Math.abs(hex1Split.g - hex2Split.g) / 255;
    const b = 1 - Math.abs(hex1Split.b - hex2Split.b) / 255;

    return (r + g + b) / 3;
}

// clears array from similar colors with threshold
function hexColorDelta(array, threshold) {
    // loop through array twice as a table to get all combinations
    for (let i = 0; i < array.length; i++) {
        for (let j = 0; j < array.length; j++) {
            // only remove the color in the second loop if similar
            if (i !== j && hexColorCalc(array[i][0], array[j][0]) > threshold) {
                array.splice(j, 1);
                j--;
            }   
        }
    }
    return array;
}

// test
const similar_1_2 = [["da542f", 3117], ["da5630", 60], ["333333", 6421]];
const similar_1_3 = [["da542f", 3117], ["333333", 6421], ["da5630", 60]];
const similar_2_3 = [["333333", 6421], ["da542f", 3117], ["da5630", 60]];
const similar_all = [["da5630", 60], ["da542f", 3117], ["da5630", 60]];
console.log(JSON.stringify(hexColorDelta(similar_1_2, 0.9)));
console.log(JSON.stringify(hexColorDelta(similar_1_3, 0.9)));
console.log(JSON.stringify(hexColorDelta(similar_2_3, 0.9)));
console.log(JSON.stringify(hexColorDelta(similar_all, 0.9)));

我希望这会有所帮助。

答案 1 :(得分:-1)

请在此处查看:https://jsfiddle.net/4ph8wozd/1/

&#13;
&#13;
// convert HEX code to RGB
function hexToRgb(hex) {
    var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
    hex = hex.replace(shorthandRegex, function (m, r, g, b) {
        return r + r + g + g + b + b;
    });

    var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);

    return result ? {
        r: parseInt(result[1], 16),
        g: parseInt(result[2], 16),
        b: parseInt(result[3], 16)
    } : null;
}
// compare colors
function luminanace(r, g, b) {
    var colorArray = [r, g, b];
    var colorFactor;
    var i;
    for (i = 0; i < colorArray.length; i++) {
        colorFactor = colorArray[i] / 255;
        if (colorFactor <= 0.03928) {
            colorFactor = colorFactor / 12.92;
        } else {
            colorFactor = Math.pow(((colorFactor + 0.055) / 1.055), 2.4);
        }
        colorArray[i] = colorFactor;
    }
    return (colorArray[0] * 0.2126 + colorArray[1] * 0.7152 + colorArray[2] * 0.0722) + 0.05;
}
function contrast(hex1, hex2) {
    var color1 = hexToRgb(hex1);
    var color2 = hexToRgb(hex2);
    if (color1 != null && color2 != null) {
        var result = (luminanace(color1.r, color1.g, color1.b)) / (luminanace(color2.r, color2.g, color2.b)); if (result < 1) result = 1 / result;

        // show result
        // Google says lowest:4.5 | enough:7 | good:14 | best:21
        var rgood = 7;
        var rbad = 4.5;
        contrastratio = result;
        switch (true) {
            case result >= rgood:
                contrastratiomessage = '<span class="cr-green">Text is well readable</span>';
                break;
            case result > rbad && result < rgood:
                contrastratiomessage = '<span class="cr-orange">Text is enough readable</span>';
                break;
            case result <= rbad:
                contrastratiomessage = '<span class="cr-red">Text is not readable!!!</span>';
                break;
            default:
        }
        document.getElementById('colors').innerHTML = contrastratiomessage;
    }
    console.log(result);
}
contrast('#fff000','#000fff');
&#13;
<div id="colors"></div>
&#13;
&#13;
&#13;