4
$\begingroup$

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.

$\endgroup$

2 Answers 2

4
$\begingroup$

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

Mathematica graphics

Therefore you may use:

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

Perhaps this?

makeNearestFunction[string_] :=
 MapThread[Rule,
   {
    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.

$\endgroup$
3
  • $\begingroup$ 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! $\endgroup$
    – cormullion
    Aug 11, 2012 at 12:53
  • $\begingroup$ @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? $\endgroup$
    – Mr.Wizard
    Aug 11, 2012 at 13:06
  • $\begingroup$ 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... :) $\endgroup$
    – cormullion
    Aug 11, 2012 at 13:46
4
$\begingroup$
makeNearestFunc1[string_String] := Nearest[Rule @@@ 
     Transpose@{Rescale@Range@StringLength@#, Characters@#}&@string]

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

makeNearestFunc2[string_String] :=
   Nearest@Thread[Rescale@Range@StringLength@# -> Characters@#] &@string

EDIT: To change the range to which the characters are mapped, use

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

instead of

Rescale@Range@StringLength@#
$\endgroup$
0

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.