2013-06-18 7 views
6

与えられた16進値に応じて最も一致する色の名前を取得しようとします。たとえば、16進数の#f00の場合は、redという色名を取得する必要があります。私は、最も近い色の名前を取得するには、現在レーベンシュタイン距離のアルゴリズムを使用し16進数に応じて最も近い色の名前を取得

'#ff0000' => 'red' 
'#000000' => 'black' 
'#ffff00' => 'yellow' 

、これまでのところうまく動作しますが、時々期待できないとして。例えば

'#0769ad' => 'chocolate' 
'#00aaee' => 'mediumspringgreen' 

ので、任意のアイデア結果が近づくためにどのように?

Array.closest = (function() { 

    // http://en.wikibooks.org/wiki/Algorithm_Implementation/Strings/Levenshtein_distance#JavaScript 
    function levDist(s, t) { 
     if (!s.length) return t.length; 
     if (!t.length) return s.length; 

     return Math.min(
      levDist(s.substring(1), t) + 1, 
      levDist(t.substring(1), s) + 1, 
      levDist(s.substring(1), t.substring(1)) + (s[0] !== t[0] ? 1 : 0) 
     ); 
    } 

    return function (arr, str) { 
     // http://stackoverflow.com/q/11919065/1250044#comment16113902_11919065 
     return arr.sort(function (a, b) { 
      return levDist(a, str) - levDist(b, str); 
     }); 
    }; 

}()); 

http://jsfiddle.net/ARTsinn/JUZVd/2/

もう一つはパフォーマンスです:

は、ここで私が最も近い色を取得するために作られたものです!これは本当に遅くなるような大きな問題があるようです(アルゴリズムなのでしょうか?)。

+1

もっと類似した色の場合は、代わりに[HSL](https://en.wikipedia.org/wiki/HSL_and_HSV)の色を使用する方がよいでしょう。 – Sirko

+1

並べ替える前に距離をあらかじめ計算しておけば、並べ替えの手順を**ロット**にすることができます。 – Pointy

+0

また、単純なデカルト距離計算を使用しない理由はわかりません。 (実際には、私は角度座標空間に変換し、HSLまたはHSV ternsの距離を行いますね) – Pointy

答えて

6

ここで、Levenshteinの距離は、文字が等しいかどうかを比較するため、実際には適切ではありません。それぞれの色を別々に確認する必要があります。79は、80のほうが、00よりずっと近くなります。

次はあなたのコードに最小限の変更を行うだけで、あなたが望むものにたくさん近いように思える:st両方が6文字の色あるときに、これが唯一の合理的な結果を与えること

Array.closest = (function() { 
    function dist(s, t) { 
     if (!s.length || !t.length) return 0; 
     return dist(s.slice(2), t.slice(2)) + 
      Math.abs(parseInt(s.slice(0, 2), 16) - parseInt(t.slice(0, 2), 16)); 
    } 

    return function (arr, str) { 
     return arr.sort(function (a, b) { 
      return dist(a, str) - dist(b, str); 
     }); 
    }; 
}()); 

注意16進コード。

あなたのコードは、最も近い色を得るために配列全体をソートする必要がないので、非効率です。その代わりに、配列をループして、最短距離を記録する必要があります。例えば

:あなたはあなたのコード内でさらに下[0]を削除する必要がありますので、この変更後Array.closest()は、単一の値ではなく配列を返すこと

Array.closest = (function() { 
    function dist(s, t) { 
     if (!s.length || !t.length) return 0; 
     return dist(s.slice(2), t.slice(2)) + 
      Math.abs(parseInt(s.slice(0, 2), 16) - parseInt(t.slice(0, 2), 16)); 
    } 

    return function (arr, str) { 
     var min = 0xffffff; 
     var best, current, i; 
     for (i = 0; i < arr.length; i++) { 
      current = dist(arr[i], str) 
      if (current < min) { 
       min = current 
       best = arr[i]; 
      } 
     } 
     return best; 
    }; 
}()); 

注意。

+0

うわー、素晴らしい!これまでのおかげで: - * * sとtの両方が6文字のカラー16進コードの場合、合理的な結果になります。* 3桁の16進数を6桁に変換しても問題ありません。 – yckart

+0

BTW:Pointy [http:// stackoverflow .com/questions/17175664/get-the-closest-color-name-hex-colorに依存する#comment24869664_17175664)ソート前に距離を事前に計算すると、さらに高速になりますか? – yckart

+1

あなたは全く並べ替えてはいけません。私の編集を見てください。 –

関連する問題