# Using MapThread over 2 lists different length with criterion on minimal differences

Say I have 2 lists

list1 = {-1179.8, -1139.3, -1118.3, -1115.6, -1095.2, -1075.1, -1054.7, 228.1, 249.1, 269.6, 290.6, 292.3, 312.7, 313.2, 333.8, 336.1, 354.2, 377.5, 1087.7, 1106.6, 1151.9}
list2 = {-1104.4, -1071.4, -1071.4, -1067.4, 263.6, 300.6, 311.6, 311.6, 312.6, 1067.6}

and I want to map them 1-1 on one another such that each element from list2 has its partner from list1 and such a partner is always different (no element of list1 is assigned twice). The mapping is defined by minimal difference in absolute value. The remaining elements from list1 will be mapped on 0.

But the function Nearest keeps duplicates.

f[x_, y_] := {x, y}

The desired output for this example is

{{-1179.8, 0}, {-1139.3, 0}, {-1118.3, 0}, {-1115.6, -1104.4},
{-1095.2, -1071.4}, {-1075.1, -1071.4}, {-1054.7, -1067.4}, {228.1, 0},
{249.1, 0}, {269.6, 263.6}, {290.6, 300.6}, {292.3, 311.6},
{312.7, 311.6}, {313.2, 311.6}, {333.8, 312.6}, {336.1, 0},
{354.2, 0}, {377.5, 0 ‌}, {1087.7, 1067.6}, {1106.6, 0}, {1151.9, 0}}
• What's the desired output? :) – Öskå Jul 4 '15 at 9:22
• Why don't you PadRight your list2 and thread over it ? – Sektor Jul 4 '15 at 9:52
• Sorry, it is here. {{-1179.8,0},{-1139.3,0},{-1118.3,0},{-1115.6,-1104.4},{-1095.2,-1071.4},{-1075.1,-1071.4},{-1054.7,-1067.4},{228.1,0},{249.1,0},{269.6,263.6},{290.6,300.6},{292.3,311.6},{312.7,311.6},{313.2,311.6},{333.8,312.6},{336.1,0},{354.2,0},{377.5,0},{1087.7,1067.6},{1106.6,0},{1151.9,0}} – kveta Jul 4 '15 at 10:08
• Can you explain why the first element is {-1179.8,0} and not {-1179.8,-1104.4}? Is it that (1) for every x in list2, there is some element in list1 that is closer to x than -1179.8, and (2) you don't allow duplicates? – march Jul 4 '15 at 13:43
• To march: Absolutely as you wrote. Value -1104.4 is closer to -1115.6 than to -1179.8 – kveta Jul 4 '15 at 14:22

I'm not sure I correctly interpreted what you really are looking for, because you mention MapThread that works on elements on the same position in the two lists, whereas in the description you say that for each element of list2 you want the closest from list1. Moreover, this means that once you selected an element from list1, it cannot be considered for further elements in list2, so the final result you get depends on the order on which you work on elements in list2. However, here is a possible solution.

CompareLists[list1_List, list2_List] := Module[{temp, selection},
temp = list1;
Map[
(selection = First@Nearest[temp, #];
temp = DeleteCases[temp, selection];

It's not so elegant but I think it does what you need. Here is the result for the list1 and list2 you provided

CompareLists[list1, list2]

(*  {{-1095.2, -1104.4}, {-1075.1, -1071.4}, {-1054.7, -1071.4}, \
{-1115.6, -1067.4}, {269.6, 263.6}, {292.3, 300.6}, {312.7,
311.6}, {313.2, 311.6}, {333.8, 312.6}, {1087.7, 1067.6}, {228.1,
0}, {249.1, 0}, {290.6, 0}, {336.1, 0}, {354.2, 0}, {377.5,
0}, {1106.6, 0}, {-1118.3, 0}, {-1139.3, 0}, {1151.9, 0}, {-1179.8,
0}} *)
• Thanks, it is almost fine. Can be your code expanded to cover minimal value check of the sum of differences instead of just minimal distance to the first assigned element? – kveta Jul 5 '15 at 8:26
• I do not understand exactly your question, however, instead of Nearest (the first row of Map, where "selection" is calculated, you can consider any other function that takes two arguments: the current element of list2 and the whole list1. That function has to return a value taken from the list1. – bobknight Jul 5 '15 at 17:32

Once you select the nearest element for list2[[1]] then other elements from list2 are practically directly assigned. There is one element from list2 not well assigned and it is -1067.4. Its partner -1115.6 is further than -1054.7. When you first reverse the order of initial lists, the desired solution is obtained. This minimize the Total value of differences in the resulting list of 2-tuples.

• This is more of a comment rather than an answer. Consider expanding on it if you wish to really answer the question – Sektor Jul 4 '15 at 21:30
• Right, I would like to. But I need 50 reputations to comment. – bosona Jul 4 '15 at 21:34
• Without checking your assertions, it sounds to me that you're close to an answer. Care to flesh it out, including code so that others can try out your idea? (P.S. You need to put @user for "user" to be notified of your response. Authors of posts are always notified of comments to their posts.) – Michael E2 Jul 4 '15 at 22:17