I'm trying to write a function that picks out the row of a Matrix whose kth element is closest to some given number that will be given to me.

So for example,

list = Table[{i, FromCharacterCode[70 + i]}, {i, 1, 10}]
{{1, "G"}, {2, "H"}, {3, "I"}, {4, "J"}, {5, "K"}, {6, "L"}, {7,"M"}, {8, "N"}, {9, "O"}, {10, "P"}}

enter image description here

b = RandomReal[{0, 6}]

So I want to pick the row whose 1st element is closest to 4.42427. The function should spit out



Btw, thanks to Mr. Wizard's help, my crappy code works!!

disT[l_List, bb_?NumericQ, cc_Integer] := Table[Abs[bb - l[[j, cc]]], {j, 1,Dimensions[l][[1]]}]

srcH[ll_List, bb_?NumericQ, cc_Integer] := Drop[First[Sort[Transpose[    Prepend[Transpose[ll], disT[ll, bb, cc]]], #1[[1]] < #2[[1]] &]],1]

{3.42427, 2.42427, 1.42427, 0.42427, 0.57573, 1.57573, 2.57573,3.57573, 4.57573,5.57573}

srcH[list, b, 1]
{4, "J"}

Now I will Implement Mr. Wizard's code or Daniel's code for my actual problem. Thanks!!


To expand on what I wrote under Mr. Wizard's answer. The actual task that I am trying to accomplish involves many lists $list_k \; k \; \in \{1,100\}$ and many comparison lists $b_k = (b_{k1},...,b_{kj}), \; \; k \; \in \{1,100\}$ .

So For example:

 list[57]=  {{1, "G"}, {2, "H"}, {3, "I"}, {4, "J"}, {5, "K"}, {6, "L"}, {7,"M"}, {8, "N"}, {9, "O"}, {10, "P"}}


 list[79]=  {{2.8, "G"}, {3.4, "H"}, {4.5, "I"}, {5.1, "J"}, {6.05, "K"}, {7.1, "L"}, {8.3,"M"}, {8.5, "N"}, {9, "O"}, {10, "P"}}


and my final output, as index goes from 1 to 100, will find rows where the first element is close to the elements of b[k] respectively:


I was planning on using the function I got from the help here at mma.se inside a table or something but since Mr. Wizard has mentioned speeding up computation, I figured it would be best if I described the exact problem I am working on.

  • $\begingroup$ How are you measuring distance from a real to a character? $\endgroup$ Oct 10 '12 at 23:33
  • $\begingroup$ @DanielLichtblau I only want to use the Distance function on columns which have real entries. $\endgroup$
    – Amatya
    Oct 10 '12 at 23:51
  • $\begingroup$ You mean the row whose first element is closest, right? $\endgroup$
    – Rojo
    Oct 11 '12 at 0:55
  • $\begingroup$ @Rojo in this example, the first element but in my actual problem some kth element. $\endgroup$
    – Amatya
    Oct 11 '12 at 1:10
  • $\begingroup$ @Rojo and Daniel .. I just noticed and fixed the typo in my question. $\endgroup$
    – Amatya
    Oct 11 '12 at 1:31

The reason I wanted this as a function is because I will wind up using it on lots of different lists for lots of different columns. I'm guess the function form is better for that.

If you are going to be using the function nearly at random, with little repetition of lists then you may do well with:

nff[num_?NumericQ, l_List] := Nearest[#[[1]] -> # & /@ list, b, 1][[1]]

If you will use the function for many columns within a single list I propose that you let Nearest built a function for you. If memory is not a limitation (the lists are not too large) then I propose using memoization to streamline this process.

m : makeNF[list_List] := m = Nearest[#[[1]] -> # & /@ list]

nffmem[num_?NumericQ, l_List] := makeNF[l][num][[1]]

This pair of functions will build a Nearest function only once for each list, caching it as a definition of makeNF. You could use ClearAll[makeNF] and then evaluate the code above to clear these cached values if memory starts to get low.

  • $\begingroup$ I just looked up memoization on wikipedia. It will take be a bit to appreciate and understand the differences between the two ways you described. To address your comment, I actually have a list of 20 different numbers each for about a 100 Matrices. So b , the comparison number, is itself a list and for each of those b's I want to find something in column k closest to it. Then I do this for a 100 Matrices, each with a unique b. This is for one set of overall parameters. So I might wind up doing 2000 such uses of the function, many many times. $\endgroup$
    – Amatya
    Oct 11 '12 at 7:09
  • $\begingroup$ @Amatya I'll be in chat for a few minutes if you want to discuss this. $\endgroup$
    – Mr.Wizard
    Oct 11 '12 at 22:43

Use Nearest.

nf = Nearest[Map[Rule[#[[1]], #] &, list]];

{4, "J"}
  • $\begingroup$ Geez man, format your code! ;-p $\endgroup$
    – Mr.Wizard
    Oct 10 '12 at 23:48
  • $\begingroup$ Oh man! good MMA code is so slick! Thanks a lot Daniel! What was I doing wrong in my disT function though? $\endgroup$
    – Amatya
    Oct 10 '12 at 23:53
  • 1
    $\begingroup$ Shorter: nf = Nearest[#[[1]] -> # & /@ list] $\endgroup$
    – Mr.Wizard
    Oct 11 '12 at 0:04
  • 1
    $\begingroup$ @Amatya you're using incorrect patterns. As written you're trying to match objects with heads list and numba which are not built-in heads in Mathematica. Also, if you are going to write this as a function that is called as shown, rather than building a function nf as Daniel's answer does, you would to better to use a different syntax for Nearest. Try this: nff[num_?NumericQ, l_List] := Nearest[#[[1]] -> # & /@ list, b, 1][[1]] $\endgroup$
    – Mr.Wizard
    Oct 11 '12 at 0:08
  • 4
    $\begingroup$ @Amatya see this slide for a summary of pattern objects. There are quite a few of them! $\endgroup$
    – Mr.Wizard
    Oct 11 '12 at 0:20

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.