# List compare

Hi everyone,

I have two lists:

``````set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

``````
1. I want to be able to see if (items 1 thru 2 of item x) of list_2 are in list_1
2. If they aren’t, return (items 1 thru 2 of item x) of list_2 (i.e., the INCORRECT value) AND what the item in list_1 is (i.e., the CORRECT value).

So for the above example lists, (items 1 thru 2 of item 2) of list_2 are NOT in list_1. So I want to return the value from list_1 of {“ABC”, “123”} to give me the correct value. I hope this makes sense. Thanks ahead of time for the help.

So it seems you only need some repeat loops and if statements… that seems like you should be able to figure it out. Is there anything in particular you’re having trouble with? What do you have so far?

Hello.

This is the brute force approach it will iterate through your list i * j times worst, case where i is the number of sublists to check, and j is the number of valid sublists.

If you have really many items in both lists, then it would be best to presort them and use a binary search algorithm to find the primary key way faster: i * ( log j + 1) comparisons (log2).

ASSUMPTIONS:
The primary keys in list one is unique, that is there is only one sublist which has “ABC” as its first item.
I also assume that there is no primary keys in the list to check which are not represented in the valid list.
I further assume that all primary keys are uppercase

``````
set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

log validateList(list_1, list_2) ”> *invalid entry : {ABC,444,111} should be{ ABC,123}
on validateList(theValid, toCheck)
script o
property l : theValid
property m : toCheck
end script
set {tids, text item delimiters} to {text item delimiters, ","}
set output to {}
set numValid to (count theValid)
considering case
repeat with i from 1 to (count toCheck)
repeat with j from 1 to numValid
if item 1 of item i of o's m is item 1 of item j of o's l then
if item 2 of item i of o's m is item 2 of item j of o's l then
exit repeat
else
set end of output to {"invalid entry : {" & item i of o's m & "} should be{ " & item j of o's l & "}" }
exit repeat
end if
end if
end repeat
end repeat
end considering
set text item delimiters to tids
return output
end validateList

``````

Wow, McUsr. When I run your script, it seems to give the right answer, but I was hoping for a more simple solution. I actually don’t care about the case-sensitivity, sorry for not clarifying that. I was just trying to give simple list item examples. To answer Hank’s question, I do have something so far, but for me, it wasn’t as easy as it was to Hank (which is why I’m asking for help :D)

Here’s what I have so far:

``````
set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

--Do the comparison
set diff_list to {}
repeat with x from 1 to length of list_1
set second_pt_list1 to (item 2 of item x of list_1)
repeat with x from 1 to length of list_2
set templist to items 1 thru 2 of (item x of list_2)
if list_1 does not contain {templist} then
set diff_list's end to templist & item -1 of (item x of list_2) & second_pt_list1
end if
end repeat
end repeat

return diff_list
--Result: {{"ABC", "444", "111", "123"}, {"ABC", "444", "111", "123"}}
``````

The result gives me what I’m looking for, but I get two copies of the result instead of only one. I’m sure it has something to do with the first repeat, but I’m kinda stumped at this point. Thanks for the help.

Here’s my take. It returns, as asked, items 1 thru 2 of the offending item from list_2, the “correct” item from list_1 (assuming they have to begin with the same code), and, for good measure, the offending item’s position in list_2:

``````set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

repeat with x from 1 to (count list_2)
set thisValue to items 1 thru 2 of item x of list_2
if ({thisValue} is not in list_1) then
set v to beginning of thisValue
repeat with y from 1 to (count list_1)
if (item y of list_1 begins with v) then return {x, thisValue, item y of list_1}
end repeat
end if
end repeat
--> {2, {"ABC", "444"}, {"ABC", "123"}}
``````

Thank you for your post, Nigel! That works wonderfully.

Hello here is another one, Nigel gave me some ideas.
This falls totally in under the readability section (hopefully).

I think it is natural to have the fewest iterations in the outer loop, and that is what Nateh did.
I have used his example. I then inverted his logic, so that I test for containment of an element in the first list.
If the element of the first list is not contained in the second list, then we are having an issue, and writes that
current element of list 2 out together with the current list element in list 1.
I should of course have added an index.
Nigels example is best as usual! Readable, and with a high potential for optimization, can just plug it right in, no rework.

If you search for it, you will find some other clever routines for finding differences and their positions here at MacScripter.

Have a good night.

``````

set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

--Do the comparison
set diff_list to {}
repeat with x from 1 to (count list_1)
set template to item x of list_1
repeat with y from 1 to (count list_2)
set templist to item y of list_2
if templist does not contain template and beginning of templist is beginning of template then
set diff_list's end to templist & template
end if
end repeat
end repeat
diff_list
--Result: {{"ABC", "444", "111", "ABC", "123"}}

``````

Hello.

And here is the last one, a minor variation of the previous.

``````
set list_1 to ¬
{{"ABC", "123"}, {"DEF", "123"}}
set list_2 to ¬
{{"ABC", "123", "000"}, {"ABC", "444", "111"}, {"DEF", "123", "222"}, {"DEF", "123", "333"}}

--Do the comparison
set diff_list to {}
repeat with template in list_1
repeat with idx from 1 to (count list_2)
set aSublist to item idx of list_2
if aSublist does not contain template and beginning of aSublist is beginning of template then
set diff_list's end to {idx, contents of aSublist, contents of template}
end if
end repeat
end repeat
diff_list
--Result: {{2, {"ABC", "444", "111"}, {"ABC", "123"}}}

``````