1
$\begingroup$

I am trying to find which string is nearest to another string in an array of numbers and strings. For example, say I have an array that is as follows

testarray={0,0,0,"apple",0,0,0,"pear",0,0,0,0,0,"pineapple"}

I want a general way to find that "apple" is nearest to "pear". Is there an efficient way to do this?

Thanks!

$\endgroup$

3 Answers 3

5
$\begingroup$

If you want to specify a string in advance and find the position of another string closest to the original, you could do something like this:

positionOfApple = Position[testarray, "apple"] 
(* {{4}} *)

closestToApple = 
  Nearest[Complement[Position[testarray, _String], positionOfApple], positionOfApple]
(* {{{8}}} *)

Extract[testarray, #] & /@ closestToApple
(* {{"pear"}} *)

If instead you are wanting to find a pair of strings with minimal distance between them...

closest = 
  MinimalBy[Partition[Position[testarray, _String], 2, 1], Abs@*Apply[Subtract]@*Flatten]
(* {{{4}, {8}}} *)

Extract[testarray, #] & /@ closest
(* {{"apple", "pear"}} *)
$\endgroup$
1
  • $\begingroup$ I'm interpreting "nearest" to be referring to position within testarray. If you mean "nearest" with regard to something like Levenshtein distance, then the answer will depend on EditDistance, or something similar. $\endgroup$
    – lericr
    May 10 at 22:16
3
$\begingroup$

Just for fun, another option is to write your own distance function

t = {0, 0, 0, "apple", 0, 0, 0, "pear", 0, 0, 0, 0, 0, "pineapple"}
nearItem = "pear";
f[x_, y_] := Module[{dist = 10^6},
  If[StringQ[y] && y != nearItem, 
     dist = Abs[Position[t, x][[1, 1]] - Position[t, y][[1, 1]]]
  ];
  dist
 ]

Nearest[t, nearItem, DistanceFunction -> f]

{"apple"}

When

t = {"apple", 0, 0, 0, 0, 0, 0, "pear", 0, 0, 0, 0, 0, "pineapple"}

It gives

{"pineapple"}

And when there are two equal distance ones, it gives

t = {0, "apple", 0, 0, 0, 0, 0, "pear", 0, 0, 0, 0, 0, "pineapple"}
{"apple", "pineapple"}

You can modify your distance function as needed.

$\endgroup$
2
$\begingroup$
testarray = {0, 0, 0, "apple", 0, 0, 0, "pear", 0, 0, 0, 0, 0, "pineapple"}

Extract positions of strings:

pos = Position[testarray, _String]

{{4}, {8}, {14}}

strs = Extract[testarray, pos]

{"apple", "pear", "pineapple"}

Make subsets of pairs:

ssets = Subsets[strs, {2}]

{{"apple", "pear"}, {"apple", "pineapple"}, {"pear", "pineapple"}}

Define a distance function:

dist[{a_, b_}] := 
 Det@Position[testarray, b] - Det@Position[testarray, a]

Transpose[{Rule @@@ ssets, dist /@ ssets}] // TableForm

$$\left( \begin{array}{cc} \text{apple}\to \text{pear} & 4 \\ \text{apple}\to \text{pineapple} & 10 \\ \text{pear}\to \text{pineapple} & 6 \\ \end{array} \right)$$

This can be sorted based on distance or as required.

$\endgroup$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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