# Creating a Nearest function programmatically

I've been trying to work out how to create a Nearest function programmatically. My goal is to produce something similar to this, a hand-assembled function:

nf = Nearest[{0.0 -> "B", 0.05 -> "W", 0.1 -> "H", 0.15 -> "h",
0.2 -> "e", 0.3 -> "c",  0.4 -> "o", 0.5 -> "'", 0.6 -> "-",
0.7 -> ":", 0.8 -> ".", 0.9 -> "-", 0.95 -> " "}];


But instead of making it by hand, and editing the values, I want to pass a string and get all the letters allocated automatically to values between 0 and 1. (This is for producing ASCII-art type versions of images.)

For example, a function that looks a bit like this:

makeNearestFunction[string_] :=
nf = Nearest[
Riffle[
Range[0, 1, N[1/StringLength[string]]], Characters[string]]
...
(* returns a nearest function *)


could be called like this:

nf = makeNearestFunction["Mathematica!:- "]


I've got as far as producing a list of data like this:

{0., "M", 0.0666667, "a", 0.133333, "t", 0.2, "h", 0.266667, "e",
0.333333, "m", 0.4, "a", 0.466667, "t", 0.533333, "i", 0.6, "c",
0.666667, "a", 0.733333, "!", 0.8, ":", 0.866667, "-", 0.933333, " ",
1.}


but the pairs need to be assembled as rules.

The threading shown in my original answer below is unnecessary as Nearest accepts this form:

Therefore you may use:

makeNearestFunction[string_] :=
Nearest[Rescale@Range@Length@# -> #] & @ Characters@string


Perhaps this?

makeNearestFunction[string_] :=
{
Most @ Range[0, 1, N[1 / StringLength@string]],
Characters @ string
}
] // Nearest


Or this?

makeNearestFunction[string_] :=
With[{len = StringLength @ string},
Nearest @ Thread[Range[0, len - 1]/len -> Characters @ string]
]


This doesn't include 1. in the function, but neither does your hand-assembled function.

• You make it look easy! :) I couldn't work out how to use the Rule function, but I see that it isn't essential. Nice one, sir! Aug 11, 2012 at 12:53
• @cormullion Thanks. I'm not sure which numeric value you want the last character to map to: 1 or one increment before 1, e.g. 0.95/0.933. What is your intent? Aug 11, 2012 at 13:06
• The 1.0 value will correspond to pure white in the original image, so it will occur rarely anyway. Or, in other words, I don't yet know... :) Aug 11, 2012 at 13:46
makeNearestFunc1[string_String] := Nearest[Rule @@@
Transpose@{Rescale@Range@StringLength@#, Characters@#}&@string]


or, a slight variation of Mr.W's second function,

makeNearestFunc2[string_String] :=

Rescale[Range@#, {1, #}, {0, (-1 + #)/#}] &@StringLength@#

Rescale@Range@StringLength@#
`