Comparing Lists

I’m sure I’m going about this all wrong. I need to compare the contents of two Excel files. Each contains a record as a row, a product code, followed by alternating rows of color codes and cells indicating whether the color in the previous cell is new or not.

I need to go through a row at a time, match records to records (i.e. product codes to product codes). Once I know I’m dealing with the same procuct records, I need to step through the colors and find matching codes, and finally, transfer the info on whether the color is new or not from one data source to the other.

My approach as been to save each Excel file as tab-delimited text and then use AS to compare them. However, the script runs and runs and never seems to finish. When I troubleshoot, each part seems OK but it won’t work in its entirety. Below is the script and a sample of the data files it requests:


------------------P R E P A R E   R E S O U R C E S---------------
set text item delimiters to return
set counter to 0
set Temper to {}
set miniList to {}
set BigList to {}

--note: DBDataMaster is data from one data source
--note: LLDataMaster is data from a file that contains the info as to whether a color is new or not

--user selects Database data file
set theFile to choose file with prompt "Choose the Database text file" of type {"TEXT"}
open for access theFile
set theDBDataMaster to read theFile using delimiter return
close access theFile

--user selects the Linelist data file
set theOtherFile to choose file with prompt "Choose the Linelist text file" of type {"TEXT"}
open for access theOtherFile
set theLLDataMaster to read theOtherFile using delimiter return
close access theOtherFile


------------------L O A D  R E C O R D  D A T A---------------
repeat with a from 1 to (count of items in theDBDataMaster)
--get the first record from the first data source
	set tester1 to item a of theDBDataMaster
--get the first record of the file to which we will compare DBDataMaster
	repeat with b from 1 to (count of items in theLLDataMaster)
		set Tester2 to item b of theLLDataMaster
		set text item delimiters to tab
--compare the first field of each record to make sure we have the same product
		if text item 1 of tester1 = text item 1 of Tester2 then
--save the product number to a variable for use later
			set theKey to text item 1 of tester1
--go through the daAtbase record a color at a time to see if we can find matching colors in the other data source, we have to go by twos because the data, after the product code goes: COLOR, NEW STATUS INDICATOR, COLOR, NEW STATUS INDICATOR, COLOR, NEW STATUS INDICATOR, ETC.
			repeat with i from 2 to count of text items in tester1 by 2
				set DBCCTest to text item i of tester1
				repeat with j from 2 to count of text items in Tester2 by 2
					set LLCCTest to text item j of Tester2
					if text item i of tester1 = text item j of tester1 then
--if we find matching colors, get the newness status of that record, paired with the corresponding color code
						try
							set Temper to {(text item i of tester1 as string), (text item (j + 1) of Tester2)}
--hold this data in a temporary lisy
							copy Temper to end of miniList
						end try
					end if
				end repeat
			end repeat
--append the product code to the beginning of the temporary list
			set miniList to {theKey, miniList}
		end if
--populate a bigger list
		copy miniList to the end of the BigList
		set miniList to {}
	end repeat
end repeat
return BigList
--set AppleScript's text item delimiters to {""}
--return finalList


Database File Sample (tab delimited)
ALWC KE4 682 472 JK3
ALWM JB8 JK3 190 GP4
ALWU GP4 85V 190 JC0 JB8 FN4 JK3
ALXB JK3 190 JC0 JB8
AMFN FM4 KE4 472 JK3
AMFP JB4 JK3 61Q FM4
AMFZ JC6 JK3 044 EY3
AMGD GP4 JC3 JK3 044
AMGF JC3 KE3 JB8 190
AMGU K69 GM4 K60 LE4
AMGV GM4 MT3 LE1 K60 LE4
AMGY FM4 JK3 682 JB4
AMGZ JB4 682 JK3 FM4
AMHA JB4 JK3
AMYX ML1 LE4 ML5 MJ3 LE2
AMYZ 190 KE3 JC3 JB8
AMZA JC3 JB8 KE3

Sample Linelist File (tab delimited)
ALWC 682 NEW 472 NEW KE4 NEW JK3 NEW
ALWM JK3 NEW 190 NEW GP4 NEW JB8 NEW
ALWU 85V 190 GP4 JC0 NEW JB8 NEW FN4 JK3
ALXB JK3 190 JC0 NEW JB8 NEW
AMFN KE4 NEW 472 NEW FM4 NEW JK3 NEW
AMFP JK3 NEW JB4 NEW 61Q NEW FM4 NEW
AMFZ JK3 NEW 044 NEW EY3 NEW JC6 NEW
AMGD GP4 NEW JC3 NEW JK3 NEW 044 NEW
AMGF KE3 NEW JB8 NEW JC3 NEW 190 NEW
AMGU GM4 NEW K69 NEW K60 NEW LE4 NEW
AMGV GM4 NEW MT3 NEW LE1 NEW K60 LE4 NEW
AMGY JK3 NEW FM4 NEW 682 JB4 NEW
AMGZ JK3 NEW 682 FM4 NEW JB4 NEW
AMHA JK3 NEW JB4 NEW
AMYX LE4 NEW ML5 NEW MJ3 NEW LE2 NEW ML1 NEW
AMYZ KE3 NEW 190 NEW JC3 NEW JB8 NEW
AMZA JB8 NEW JC3 NEW KE3 NEW

Linelist File Sample

I didn’t go through your code in too much detail, but one line in particular looks wrong. I think this line…

 if text item i of tester1 = text item j of tester1 then

should be…

 if DBCCTest = LLCCTest then

Also, I would read the files using “paragraphs” instead of “using delimiter return” because sometimes the line ending could be different than the return character. It might be a unix line ending instead and “paragraphs” adjusts itself for the line endings. So try these too…

set theDBDataMaster to paragraphs of (read theFile)
 set theLLDataMaster to paragraphs of (read theOtherFile)

Hello

I have done some minor fixes to your code and this is the resulting output:

Output after run: ALWC KE4 NEW 472 NEW ALWM JB8 NEW 190 NEW ALWU GP4 JC0 ALXB JK3 190 JC0 NEW AMFN FM4 NEW 472 NEW AMFP JB4 NEW 61Q NEW AMFZ JC6 NEW 044 NEW AMGD GP4 NEW JK3 NEW AMGF JC3 NEW JB8 NEW AMGU K69 NEW K60 NEW AMGV GM4 NEW LE1 NEW AMGY FM4 NEW 682 JB4 AMGZ JK3 NEW AMHA JB4 NEW AMYX ML1 NEW ML5 NEW LE2 NEW AMYZ 190 NEW JC3 NEW AMZA JC3 NEW KE3 NEW
I changed the line


     if text item i of tester1 = text item j of tester1 

Into this:


        if text item i of tester1 = text item j of Tester2 then

I also added this, at least as a convenience when looking at the BigList in the Debugger, but
I also believes it prevents some unnecessary testing when converting the text back.
” from where you just copy it to the end.


    if not miniList is {} then
            copy miniList to the end of the BigList
            set miniList to {}
        end if

speaking of conversion back:


set text item delimiters to tab
repeat with aLine in BigList
    
    set indicators to item 2 of aLine
    set text item delimiters to tab
    set tmpBuf to {}
    repeat with aPair in indicators
        set aPair to contents of aPair as text
        set end of tmpBuf to aPair
    end repeat
    set contents of aLine to contents of item 1 of aLine & tmpBuf as text
    
end repeat
set text item delimiters to return
set BigList to BigList as text


Before I eventually start to optimize your code, I’d like to now the size of your data.

Brilliant McUsr and regulus6633! Thanks. I can’t believe I didn’t catch that line where I was comparing two items in the same list rather than two corresponding items in different lists. Thanks to for the script to extract the output to a more usable, tab-delimited format.

In answer to McUsr’s question, I will likely use this on tab-delimited text files of 200-300 rows (records) with each row containing between 10 and 30 items (fields).

Hello.

Before doing anything I want to know if you agree to the following statements, or have something you wish to comment.

For each and every line of the “main” table there is only one corresponding line in the lines table

Any superfluous codes in the lines table is disregarded: you are only concerned with the codes of the main table.

The two files are always sorted on the “code” field.

The codes are unique i.e a code in the main or the lines table can only be represented by one line.

The codes and everything is all uppercase like in the provided excerpts of text files

Hello.

This script works under the assumptions stated above and should run at least approximate 30% faster.
That is: the first version executed in 0.028 seconds and this version in 0.02 seconds.
I your computer is 10 times slower than mine and it the amount of the data is as you have specified then the script should grossly execute in 230 seconds, or close to 4 minutes. If you have computer like mine it should take some 23 seconds or slightly more with 300 rows and 15 keys per row.

The calculations for those estimates are that it took 0.02 seconds with this version to execute 17174 iterations,
and what has to be done is 30030015 iterations. No concern of “shaved off loops” nor file access time.

I’d still be curious to here what time it takes to execute so I have included some timing code.

In order to use the timing code you must download the timer tools from here and adjust the path to it in the
do shell script statement accordingly.

If that is too much work, or difficult for you then just rip it out.

You could use something like :


set time1 to (current date)

in the start of the code
and


set time2 to (current date) - time1
display dialog "" & time2

At the end of your code
The amount of optimizing from now on is limited, still it would be interesting to know.

This inclusion is not totally how I tested it when achieving those results because I have hardcoded the file paths,
and performed the initial timing as the first executing statements.

Please post your results


script timeTools
	” © McUsr 2010
	--	property parent : AppleScript
	property getMillisec : missing value
	
	on firstMillisec()
		local overhead
		my realgetMillisec() -- gets stuff loaded into mem for later, this first call takes longer time.
		set my getMillisec to my realgetMillisec
		set _overhead to -(my realgetMillisec()) + 2 * (my realgetMillisec()) -- Nigel Garvey
		return _overhead
	end firstMillisec
	
	on realgetMillisec()
		local res
		set res to do shell script "/usr/local/opt/timetools -ums"
		-- you must change path to your hardcoded path to timetools,
		return res
	end realgetMillisec
	on run
		set my getMillisec to my firstMillisec
	end run
end script

------------------P R E D E F I N E  R E S O U R C E S---------------
property theDBDataMaster : {}
property theOtherFile : {}

property tester1 : {}
property Tester2 : {}
property BigList : {}
property aLine : {}
------------------P R E P A R E   R E S O U R C E S---------------
set text item delimiters to return
set counter to 0
set Temper to {}
set miniList to {}

set mainKey to {}
set linesKey to {}


global i, j
--note: DBDataMaster is data from one data source
--note: LLDataMaster is data from a file that contains the info as to whether a color is new or not


--user selects Database data file
set theFile to choose file with prompt "Choose the Database text file" of type {"TEXT"}
open for access theFile
set theDBDataMaster to read theFile using delimiter return
close access theFile

--user selects the Linelist data file
set theOtherFile to choose file with prompt "Choose the Linelist text file" of type {"TEXT"}
open for access theOtherFile
set theLLDataMaster to read theOtherFile using delimiter return
close access theOtherFile
” T I M I N G  C O D E
tell timeTools to run
set t to timeTools's getMillisec()
set c to 0
considering case
	------------------L O A D  R E C O R D  D A T A---------------
	repeat with a from 1 to (count of items in theDBDataMaster)
		--get the first record from the first data source
		set tester1 to item a of my theDBDataMaster
		--get the first record of the file to which we will compare DBDataMaster
		
		set c to c + 1
		
		
		repeat with b from c to (count of items in theLLDataMaster)
			set Tester2 to item b of my theLLDataMaster
			set text item delimiters to tab
			--compare the first field of each record to make sure we have the same product
			if text item 1 of my tester1 = text item 1 of my Tester2 then
				set c to b -- new starting point
				--save the product number to a variable for use later
				set theKey to text item 1 of my tester1
				--go through the daAtbase record a color at a time to see if we can find matching colors in the other data source, we have to go by twos because the data, after the product code goes: COLOR, NEW STATUS INDICATOR, COLOR, NEW STATUS INDICATOR, COLOR, NEW STATUS INDICATOR, ETC.
				repeat with i from 2 to count of text items in tester1 by 2
					set DBCCTest to text item i of my tester1
					repeat with j from 2 to count of text items in Tester2 by 2
						set LLCCTest to text item j of my Tester2
						if text item i of my tester1 = text item j of my Tester2 then
							--if we find matching colors, get the newness status of that record, paired with the corresponding color code
							try
								set Temper to {(text item i of my tester1 as string), (text item (j + 1) of my Tester2)}
								--hold this data in a temporary lisy
								copy Temper to end of miniList
							end try
						end if
					end repeat
				end repeat
				--populate a bigger list
				if not miniList is {} then
					--append the product code to the beginning of the temporary list
					set miniList to {theKey, miniList}
					copy miniList to the end of the BigList
					set miniList to {}
				end if
				
			else if text item 1 of my tester1 < text item 1 of my Tester2 then
				set c to c - 1 -- tries next row from previous pos
				exit repeat
			end if
		end repeat
	end repeat
end considering
set text item delimiters to tab
repeat with i from 1 to (count BigList)
	set aLine to item a of my BigList
	set indicators to item 2 of my aLine
	set text item delimiters to tab
	set tmpBuf to {}
	repeat with aPair in indicators
		set aPair to contents of aPair as text
		set end of tmpBuf to aPair
	end repeat
	set aLine to contents of item 1 of my aLine & tmpBuf as text
	
end repeat
set text item delimiters to return
set BigList to BigList as text
set res to ((timeTools's getMillisec()) - t) / 1000
display dialog "" & res

return BigList

Hi McUsr:

Your improved script works great. I haven’t had time to go through it and lean from your optimization. I’ve been wrestling with some byte order marks that have been cropping up in the data which will through the script off. Thanks for all your help. I’ll be back in touch soon.

Hello harges.

Please get your self a free copy of TextWrangler if you don’t have it already, there you should be able to easily see
what kind of file type it will be interpreted as. You can download TextWrangler for free at BareBones Software.

And do come back and tell me about your problems with the byte ordering. :smiley: I’m kind of eager on this…

I have written a script that keeps the data in the Excel files instead of requiring dumping to text files. I’ve attempted to think of the different options you might need in the application and included them as optional. One option that I assumed was that the Big List color data in each row can be sorted by color.
I’ve run this on my 2009 MacBook and it takes ~45 seconds to do everything, with the files already loaded in Excel, for a database of 90 part numbers with up to 10 colors, a Line file with 80 part numbers with up to 10 colors, which is all merged into the Big List at 103 part numbers by up to 10 colors. 25 part numbers in the database are absent from the Line file and 25 line part numbers are absent from the database. Many colors are different between the same part numbers in the files.

Although this takes longer than the simple text work, it saves time overall as there is no need to convert Excel files back and forth, etc.

As a first time poster, and relative noob, I look forward to feedback and if this is of value to the OP.

-------------------
--notes: assumes there are no duplicated part number rows in data file or duplicate rows in line file
-- written for Excel 2008 on Snow Leopard
-- depends on three files: Database, Line, and Big List
-- case is ignored here, need to modify if case is significant to part numbers or colors
-- assumes it is ok to sort the color ids in the Big List for ease of reviewing (and procesing, actually)
-- Database can have unique part numbers (not in Line file) and vice versa
--  database and Line rows can have diferent colors in them, they are combined into the BL
-- there are several property options one can or must set
--  the code as written expects sorting to be true of both database and Line color data when converting to Big List (missing AS code for not sorted)
-- The code assumes the database and Line may or may not be sorted by part number already, so it tells Excel to sort
-- if there is a missing color value in the middle of a line or database row, this blank is eliminated when converting to Big List

property BLFileName : "Big List.xls" --name of the database file
property BLFilePath : "Users:papa:Downloads:" & BLFileName
property BLSheetName : "Big List" --worksheet name
property DataFileName : "Database.xls" --name of the database file
property DataFilePath : "Users:papa:Downloads:" & DataFileName
property DataSheetName : "Database file.txt" --worksheet name
property LineFileName : "Line.xls" --name of the Line info file
property LineFilePath : "Users:papa:Downloads:" & LineFileName
property LineSheetName : "Line file.txt" --worksheet name
property firstBLCol : "A" --where will big list start (column)        (don't need end cell as it is created as we go)
property firstBLRow : 1 --where will Big List start (row)
property firstDataCol : "A"
property lastDataCol : "AL"
property sortDataCol : "A:A" --the column to sort the worksheet on (part numbers) and to use for comparing
property firstLineCol : "A"
property lastLineCol : "AL"
property sortLineCol : "A:A" --the column to sort the worksheet on (part numbers) and to use for comparing
property firstDataRow : 1
property firstLineRow : 1
property startDataRangeCell : firstDataCol & firstDataRow --the top left cell of the database info
property startLineRangeCell : firstLineCol & firstLineRow --the top left cell of the Line info
property PreSortedData : false --is the database file already sorted?
property PreSortedLine : false --is the Line file already sorted?
property skipUniqueLineData : false --if there is a color value in Line that does not show in database, add or skip
property addNewLinePartNumbers : true -- if there are new Line part numbers (not in database) then add to big list or ignore
property sortDataColors : true --sort the colors in each row? Not asked for but increases efficiency slightly
property sortLineColors : true --sort the colors in each row? Not asked for but increases efficiency slightly
property FilesNotOpen : false --are the files not loaded already?
-----------------
global lastDataRow -- not a property as could change below and between runs and then get screwed up
global lastLineRow -- not a property as could change below and between runs and then get screwed up
set lastDataRow to 300
set lastLineRow to 300
global endDataRangeCell --the bottom right cell of the database info
set endDataRangeCell to lastDataCol & lastDataRow
global endLineRangeCell --the bottom right cell of the Line info
set endLineRangeCell to lastLineCol & lastLineRow
global currentBLRow -- what row will be copied to
set currentBLRow to firstBLRow
global lastDataColNum
set lastDataColNum to ConvertASCII(lastDataCol)
global lastLineColNum
set lastLineColNum to ConvertASCII(lastLineCol)
-----
if FilesNotOpen is true then -- can modify to check if files open, if not then load
	tell application "Microsoft Excel"
		open DataFilePath
		open LineFilePath
		open BLFilePath -- or create the workbook, if does not exist yet
	end tell
end if
-----
if PreSortedData is false then my SortSheet(DataFileName, DataSheetName, startDataRangeCell, endDataRangeCell, sortDataCol)
if PreSortedLine is false then my SortSheet(LineFileName, LineSheetName, startLineRangeCell, endLineRangeCell, sortLineCol)

set DataCompareCol to GetFirstCol(DataFileName, DataSheetName, sortDataCol)
set LineCompareCol to GetFirstCol(LineFileName, LineSheetName, sortLineCol)

set lastDataRow to length of DataCompareCol --takes the huge number (from property) and brings it into accuracy
set lastLineRow to length of LineCompareCol --takes the huge number (from property) and brings it into accuracy

set BigList to DoComparisonMerge() -- primary handler that does the bulk of the work or farms out to subroutines
ProcessResult(BigList) --  sends the result to Excel by row, sorted by pn and each row sorted by color


--  ==========  this sorts a worksheet into part number ascending order

on SortSheet(XLFileName, XLSheetName, startRangeCell, endRangeCell, XLSortCol)
	tell application "Microsoft Excel"
		tell workbook XLFileName
			tell worksheet XLSheetName
				sort range (startRangeCell & ":" & endRangeCell) key1 (range XLSortCol) orientation sort columns order1 sort ascending without header
			end tell
		end tell
	end tell
end SortSheet

--  ==========  get the first colum (part numbers) to use for comparing

on GetFirstCol(XLFileName, XLSheetName, XLSortCol)
	tell application "Microsoft Excel"
		tell workbook XLFileName
			tell worksheet XLSheetName
				set ComparisonList to {}
				set sourceRange to range XLSortCol
				copy range sourceRange
			end tell
		end tell
	end tell
	set ComparisonList to DoClipToList(return)
	set LineResult to {}
	repeat with counter1 from 1 to count of ComparisonList
		if item counter1 of ComparisonList ≠ "" then
			set end of LineResult to item counter1 of ComparisonList
		else
			exit repeat
		end if
	end repeat
	set text item delimiters to ""
	return LineResult
end GetFirstCol

--  ========== compare the line versus database info and use this to get data into rows for big list

on DoComparisonMerge()
	local ResultingList
	set ResultingList to {}
	repeat with DataCounter from 1 to lastDataRow
		set DataItem to item DataCounter of my DataCompareCol --take pn from left column
		if DataItem ≠ "" then
			repeat with LineCounter from 1 to lastLineRow
				set LineItem to item LineCounter of my LineCompareCol -- take pn from left column
				if LineItem ≠ "" then
					if DataItem < LineItem then
						--if the compared Line row has a part # > Data row part #, process this Data part # as it will not be matched (all line part #s are greater than it)
						CopyRow(DataFileName, DataSheetName, firstDataCol, lastDataCol, DataCounter)
						set text item delimiters to tab
						set tempList1 to the clipboard
						set tempList2 to text items of tempList1 as list
						set tempList1 to DropBlanks(tempList2)
						if sortDataColors is true then --sort data colors
							set thePN to item 1 of tempList1
							set colorList to rest of tempList1
							set tempList1 to SwapSort(colorList)
							set beginning of tempList1 to thePN
						end if
						set tempList1 to InsertStat(tempList1)
						set end of ResultingList to tempList1 as list
						set text item delimiters to ""
						--InsertValueToRow()
						set item DataCounter of my DataCompareCol to ""
						exit repeat
					else if LineItem < DataItem then
						if addNewLinePartNumbers is true then -- this is a pn in the Line file but not in the database yet
							--if compared Line row has a part # < Data row part #, process this Line part # as it will not be matched (all Data part #s are greater than it)
							CopyRow(LineFileName, LineSheetName, firstLineCol, lastLineCol, LineCounter)
							set text item delimiters to tab
							set tempList1 to the clipboard
							set tempList2 to text items of tempList1 as list
							set tempList1 to DoCompresLineRow(tempList2)
							if sortLineColors is true then --sort line colors, keeping associated status fields with them
								set thePN to item 1 of tempList1
								set colorList to rest of tempList1
								set tempList1 to SwapSortPairs(colorList)
								set beginning of tempList1 to thePN
							end if
							set end of ResultingList to tempList1 as list
							set text item delimiters to ""
							--InsertValueToRow()
							set item LineCounter of my LineCompareCol to ""
						end if
					else if LineItem = DataItem then
						set TempDataRowList to {}
						set TempLineRowList to {}
						-- copy data row
						CopyRow(DataFileName, DataSheetName, firstDataCol, lastDataCol, DataCounter) -- copy the current data row to the clipboard
						-- convert clipboard to data list
						set TempDataRowList to DoClipToList(tab)
						--drop Data row blanks
						set TempDataRowList to DropBlanks(TempDataRowList)
						-- sort data row, if flag set
						if sortDataColors is true then --sort data colors
							set thePN to item 1 of TempDataRowList
							set colorList to rest of TempDataRowList
							set TempDataRowList to SwapSort(colorList)
							set beginning of TempDataRowList to thePN
						end if
						-- copy line row
						CopyRow(LineFileName, LineSheetName, firstLineCol, lastLineCol, LineCounter) -- copy line row w/ same part # to clipboard
						-- convert clipboard to line list
						set TempLineRowList to DoClipToList(tab)
						-- compress row, only drop trailing blanks and blank color cells  as status are important and may be blank
						set TempLineRowList1 to DoCompresLineRow(TempLineRowList)
						-- sort line row, if flag set
						if sortLineColors is true then --sort line colors, keeping associated status fields with them
							set thePN to item 1 of TempLineRowList1
							set colorList to rest of TempLineRowList1
							set TempLineRowList to SwapSortPairs(colorList)
							set beginning of TempLineRowList to thePN
						end if
						-- compare rows, add NEW to data, if flag set, add any unique line info to data
						set TempRow to DoCompare(TempDataRowList, TempLineRowList)
						set end of ResultingList to TempRow
						-- copy to BL
						set item DataCounter of my DataCompareCol to ""
						set item LineCounter of my LineCompareCol to ""
						exit repeat
					end if
				end if
			end repeat
		end if
	end repeat
	return ResultingList
end DoComparisonMerge

--  ========== copy row to Clipboard

on CopyRow(theFileName, theSheetName, theFirstCol, theLastCol, theRow)
	tell application "Microsoft Excel"
		tell workbook theFileName
			tell worksheet theSheetName
				set sourceRange to range (theFirstCol & theRow & ":" & theLastCol & theRow)
				copy range sourceRange
				set tempList to the clipboard
			end tell
		end tell
	end tell
end CopyRow

--  ========== paste into BL

on InsertValueToRow(destRange, tempList)
	tell application "Microsoft Excel"
		tell workbook BLFileName
			tell worksheet BLSheetName
				set destRange to range (destRange)
				set value of destRange to tempList as list
				set currentBLRow to currentBLRow + 1
			end tell
		end tell
	end tell
end InsertValueToRow

--  ==========  convert clipboard to row list

on DoClipToList(tidUnit)
	set TempRow to the clipboard -- set temporary variable to clipbiard
	set text item delimiters to tidUnit
	set TempRowList to text items of TempRow -- converts the temp var to a list
	set text item delimiters to ""
	return TempRowList
end DoClipToList

--  ==========   eliminate blanks from a row

on DropBlanks(RowData)
	set RowResult to {}
	repeat with counter1 from 1 to length of RowData
		if item counter1 of RowData ≠ "" then
			set end of RowResult to item counter1 of RowData
		end if --  cannot do an exit repeat (after x blanks) as unsure if there is allowed to be many/any blanks in the midst of a row
	end repeat
	return RowResult -- this Data row has no blanks, including no blanks for status (NEW), which are added later
end DropBlanks

--  ========== compress line row to only cells with color data and associated status

on DoCompresLineRow(RowLine)
	set RowResult to {}
	set end of RowResult to item 1 of RowLine -- the part number
	repeat with counter1 from 2 to length of RowLine by 2
		if item counter1 of RowLine ≠ "" then
			if counter1 + 1 > length of RowLine then
				set LineColorStat to "" -- covers case if the Line row filled cells = length but last cell is color, not status as it was blank
			else
				set LineColorStat to item (counter1 + 1) of RowLine
			end if
			set end of RowResult to item counter1 of RowLine
			set end of RowResult to LineColorStat
		end if --  cannot do an exit repeat (after 2 or more blanks) as unsure if there is allowed to be any blankcolor cells in the midst of a row
	end repeat
	return RowResult -- no blank cells for colors, yet there are for status
end DoCompresLineRow

--  ==========  a sort routine based on work from someone else

on SwapSort(tempList) --  by default ignores case, change if you want to use lower case letters in part numbers
	set lengthList to length of tempList
	if lengthList < 2 then return tempList
	set swapDone to true
	repeat while swapDone
		set swapDone to false
		repeat with counter1 from 1 to lengthList - 1
			if item counter1 of tempList > item (counter1 + 1) of tempList then
				set tempSwapItem to item counter1 of tempList
				set item counter1 of tempList to item (counter1 + 1) of tempList
				set item (counter1 + 1) of tempList to tempSwapItem
				set swapDone to true
			end if
		end repeat
		set lengthList to lengthList - 1
	end repeat
	return tempList
end SwapSort

--  ==========  a sort routine based on work from someone else that does the color/status pair at once

on SwapSortPairs(tempList) --  by default ignores case, change if you want to use lower case letters in part numbers
	set lengthList to length of tempList
	if lengthList < 3 then return tempList
	if lengthList mod 2 = 1 then
		set lengthList to lengthList + 1
		set the end of tempList to ""
	end if
	set swapDone to true
	repeat while swapDone
		set swapDone to false
		repeat with counter1 from 1 to (lengthList - 2) by 2
			if item counter1 of tempList > item (counter1 + 2) of tempList then
				set tempSwapColorItem to item counter1 of tempList
				set tempSwapStatusItem to item (counter1 + 1) of tempList
				set item counter1 of tempList to item (counter1 + 2) of tempList
				set item (counter1 + 1) of tempList to item (counter1 + 3) of tempList
				set item (counter1 + 2) of tempList to tempSwapColorItem
				set item (counter1 + 3) of tempList to tempSwapStatusItem
				set swapDone to true
			end if
		end repeat
		set lengthList to lengthList - 2
	end repeat
	return tempList
end SwapSortPairs

--  ==========  compare the two rows

on DoCompare(DataRow, LineRow)
	set TempRow to {}
	set lengthDataRow to length of DataRow
	set lengthLineRow to length of LineRow
	set newDataRow to {}
	set end of newDataRow to item 1 of LineRow
	repeat with counterLine from 2 to lengthLineRow by 2
		set foundMatch to false
		set LineItem to item counterLine of LineRow
		if counterLine + 1 > lengthLineRow then
			set LineColorStat to "" -- covers case if the Line row filled cells = length but last cell is color, not status as it was blank
		else
			set LineColorStat to item (counterLine + 1) of LineRow
		end if
		if sortDataColors is true and sortLineColors is true then --if have sorted the data/Line colors, then can do this trick
			repeat with counterData from 2 to lengthDataRow
				set DataItem to item counterData of DataRow
				if DataItem is not "" then
					if DataItem < LineItem and counterData = lengthDataRow then
						if skipUniqueLineData is false then -- this means add the unique item to the data row
							set the end of newDataRow to DataItem
							set the end of newDataRow to ""
							set item counterData of DataRow to ""
							set DataItem to ""
							set the end of newDataRow to LineItem
							set the end of newDataRow to LineColorStat
							set foundMatch to true
							exit repeat
						end if
					end if
					if DataItem > LineItem then --means Line row unique vs Data row 
						if skipUniqueLineData is false then -- this means add the unique item to the data row
							set the end of newDataRow to LineItem
							set the end of newDataRow to LineColorStat
							set foundMatch to true
							exit repeat
						end if
						if counterLine = lengthLineRow - 1 then -- means the line row is done but more data elements remain
							set the end of newDataRow to DataItem
							set the end of newDataRow to ""
							set item counterData of DataRow to ""
							set DataItem to ""
						end if
					else if DataItem < LineItem then
						set the end of newDataRow to DataItem
						set the end of newDataRow to ""
						set item counterData of DataRow to ""
						set DataItem to ""
					else if DataItem = LineItem then -- the two items are equal
						set the end of newDataRow to LineItem
						set the end of newDataRow to LineColorStat
						set item counterData of DataRow to ""
						set DataItem to ""
						set foundMatch to true
						exit repeat
					end if
				end if
			end repeat
		else if sortDataColors is false then --if have sorted the data/Line colors, then can do this trick
			-- for someone else to do
		else if sortLineColors is false then --if have sorted the data/Line colors, then can do this trick
			-- for someone else to do
		end if -- end of processing if sort data was true
		if foundMatch = false then --means the Line color did not match any criteria
			if skipUniqueLineData is false then -- this means add the unique item to the data row
				set the end of newDataRow to item counterLine of LineRow
				set the end of newDataRow to LineColorStat
			end if
		end if
	end repeat
	return newDataRow
end DoCompare

--  ==========  takes result and sends to Excel by item (which is a list in itself)

on ProcessResult(BigList)
	set LengthBL to length of BigList
	set firstRangeAddrCol to firstBLCol
	repeat with counter1 from 1 to LengthBL
		set BLItem to item counter1 of BigList
		set LengthBLItem to the length of BLItem
		set secondRangeAddrCol to ConvertToASCII(LengthBLItem)
		set destRange to firstRangeAddrCol & currentBLRow & ":" & secondRangeAddrCol & currentBLRow
		InsertValueToRow(destRange, BLItem)
	end repeat
end ProcessResult


--  ========== this inserts status cells into database records that were not found in line file

on InsertStat(tempList)
	set lengthList to the length of tempList
	if lengthList < 3 then return tempList
	set tempList1 to {}
	set end of tempList1 to item 1 of tempList
	set end of tempList1 to item 2 of tempList
	repeat with counter1 from 3 to lengthList
		set end of tempList1 to ""
		set end of tempList1 to item counter1 of tempList
	end repeat
	set end of tempList1 to ""
	return tempList1
end InsertStat

--  ==========  convert alpha end cell identifier to count of column

on ConvertASCII(endValue)
	if length of endValue is 2 then
		set startletter to character 1 of endValue
		set endletter to character 2 of endValue
		set startlettervalue to ((ASCII number (startletter)) - (ASCII number ("A")) + 1) * 26
		set endCalc to startlettervalue + ((ASCII number (endletter)) - (ASCII number ("A")) + 1)
	else
		set endCalc to ((ASCII number (endValue)) - (ASCII number ("A")) + 1)
	end if
	return endCalc
end ConvertASCII

--  ==========  convert numeric to alpha for column identifier

on ConvertToASCII(numericValue)
	set lowerLetterNum to numericValue mod 26
	if lowerLetterNum > 0 then
		set lowerLetterNum to lowerLetterNum - 1
	else
		set lowerLetterNum to 26
	end if
	set lowerLetterAlpha to ASCII character ((ASCII number ("A")) + lowerLetterNum)
	set upperLetterAlpha to ""
	if numericValue > 26 then
		set upperLetterNum to numericValue div 26
		set upperLetterNum to upperLetterNum - 1
		set upperLetterAlpha to ASCII character ((ASCII number ("A")) + upperLetterNum)
	end if
	set AlphaCol to upperLetterAlpha & lowerLetterAlpha
	return AlphaCol
end ConvertToASCII

Hello oldmanegan!

I have read your code and your solution to the problem. I’ll leave it up the OP to comment on your solution.
First of all, I have not run your solution, since I don’t have the data.

I just wanted to say that I have learned a lot about scripting Excel by reading your code and as such it should be a recommended read for anybody with aspirations in that direction (said by a newbie of Excel AppleScripting).
I’m not a newbie to programming however, and I really enjoyed reading your code, which appear to be robust, and is commented, and easy to read and understand without any further explanations.

This was for me a very good how to on AppleScripting Excel 2008.

I hope you have some examples covering pivot tables to share with us! (I’m sure you have). Or other things covering other parts of Excel. I can really learn from you!

Guys,
I did a time check on the AS I submitted and it takes x seconds for each copy of a range to clipboard and parsing to a list. I am going to rewrite it to a copy of the whole database contents or line contents to clip then parse into lists for comparison. Seems like a copy of a row or a copy of a range of rows takes the same amount of time.
I believe I can drop processing down substantially for 100 part numbers, as a metric.

OldManEgan

Here is the new and improved script.
It takes 24 seconds to process 108 database rows by average of 10 columns with a 108 row Line with an average of 10-12 columns for a total of 133 resulting Big List rows, as there as some unique database and some line rows. Less than 50% of the time it took before.

Changes versus the original:
Processes the copy function as a huge range for each of database and line spreadsheets
Fixes two bugs… if unique rows at end of database or end of line spreadsheets they were missed.
Added the millisec timing functions to see what processes take how much time.

Found that the conversion of clipboard (in Excel) to variable in AS takes a long time. Maybe someone else has a resolution of this.
Cannot use the bulk entry of Big List values as each row may have a different number of columns and any blank columns in a huge value function entry over multiple rows causes a problem.


-------------------
--notes: assumes there are no duplicated part number rows in data file or duplicate rows in line file
-- written for Excel 2008 on Snow Leopard
-- depends on three files: Database, Line, and Big List
-- case is ignored here, need to modify if case is significant to part numbers or colors
-- assumes it is ok to sort the Big List for ease of reviewing (and procesing, actually)
-- Database can have unique part numbers (not in Line file) and vice versa
--  database and Line rows can have diferent colors in them, they are combined into the BL
-- there are several options below one can or must set
--	assumes there are no blank rows in database or line spreadsheets
-- The code assumes the database and Line may or may not be sorted by part number already, so it tells Excel to sort
-- if there is a missing color value in the middle of a line or database row, this blank is eliminated when converting to Big List
--  no header row is used here, so do not include header row in the rows to be processed
-- Database and Line cells must be in 'text' format, including the numbers, pre-format Big List to 'Text' format as well

----------	Adjust these to meet your needs
property DoTimingCheck : true --	this turns on timing reports to log, slows script a little (very little)
property skipUniqueLineColors : false --if there is a color value in Line that does not show in database, add or skip
property addNewLinePartNumbers : true -- if there are new Line part numbers (not in database) then add to big list or ignore
property BLFileName : "Big List.xls" --name of the database file
property BLFilePath : "Users:papa:Downloads:" & BLFileName
property BLSheetName : "Big List" --worksheet name
property sortBLColors : true --	this is the value that really counts for sorting, not the database or line
property firstBLCol : "A" --where will big list start (column)        (don't need end cell as it is created as we go)
property lastDataCol : "AL" --  adjusted later on
property lastDataRow : 300 -- adjuated later on
property lastLineCol : "AL" -- adjuated later on
property lastLineRow : 300 -- adjuated later on
property rightBLCol : "AL" -- adjuated later on
property lastBLRow : 300 -- this is adjusted later...
property getMillisec : missing value
property myRecord : {}

----------   Adjust these values as well to customize for your use
global currentBLRow -- what row will be copied to
set DataFileName to "Database.xls" --name of the database file
set DataFilePath to "Users:papa:Downloads:" & DataFileName
set DataSheetName to "Database file.txt" --worksheet name
set LineFileName to "Line.xls" --name of the Line info file
set LineFilePath to "Users:papa:Downloads:" & LineFileName
set LineSheetName to "Line file.txt" --worksheet name
set firstDataRow to 1
set firstLineRow to 1
set firstDataCol to "A"
set sortDataCol to "A:A" --the column to sort the worksheet on (part numbers) and to use for comparing
set firstLineCol to "A"
set sortLineCol to "A:A" --the column to sort the worksheet on (part numbers) and to use for comparing
set rangeDataCol to "A:A" --firstDataCol & firstDataRow & ":" & firstDataCol & lastDataRow
set rangeLineCol to "A:A" --firstLineCol & firstLineRow & ":" & firstLineCol & lastLineRow
set startDataRangeCell to firstDataCol & firstDataRow --the top left cell of the database info
set startLineRangeCell to firstLineCol & firstLineRow --the top left cell of the Line info
set endDataRangeCell to lastDataCol & lastDataRow
set endLineRangeCell to lastLineCol & lastLineRow
set FilesNotOpen to false --are the files not loaded already?
set firstBLRow to 1 --where will Big List start (row)
set sortBLCol to "A:A" --column to sort the Big List on (part numbers)
set leftBLCol to "A"
set currentBLRow to firstBLRow
set startBLRangeCell to firstBLCol & firstBLRow --top left in BL range
set endBLRangeCell to rightBLCol & lastBLRow -- adjust as needed, bottom right cell in range


------ timing routines
script timeTools
	
	on firstMillisec()
		local overhead
		my realgetMillisec() -- gets stuff loaded into mem for later, this first call takes longer time.
		set my getMillisec to my realgetMillisec
		set _overhead to -(my realgetMillisec()) + 2 * (my realgetMillisec()) -- Nigel Garvey
		return _overhead
	end firstMillisec
	
	on realgetMillisec()
		local res
		set res to do shell script "/Library/UnixApps/timetools -ums"
		return res
	end realgetMillisec
	
	on run
		set my getMillisec to my realgetMillisec --firstMillisec, crashes if I use it with firstMillisec...???
	end run
end script
-----

if FilesNotOpen is true then -- can modify to check if files open, if not then load
	tell application "Microsoft Excel"
		open DataFilePath
		open LineFilePath
		open BLFilePath -- or create the workbook, if does not exist yet
	end tell
end if
-----

-----
if DoTimingCheck is true then
	tell timeTools to run
	set t to timeTools's getMillisec()
	log "Start timing, files loaded..."
end if
----
my SortSheet(DataFileName, DataSheetName, startDataRangeCell, endDataRangeCell, sortDataCol, "Data")
my SortSheet(LineFileName, LineSheetName, startLineRangeCell, endLineRangeCell, sortLineCol, "Line")
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res & " Worksheets sorted by Excel..."
	set lastTime to res
end if
----
set rangeDataCol to firstDataCol & firstDataRow & ":" & firstDataCol & lastDataRow
set rangeLineCol to firstLineCol & firstLineRow & ":" & firstLineCol & lastLineRow
----
set DataCompareCol to GetFirstCol(DataFileName, DataSheetName, rangeDataCol) -- gets the part number column
set LineCompareCol to GetFirstCol(LineFileName, LineSheetName, rangeLineCol) -- gets the part number column
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Got 'A' column ranges..."
	set lastTime to res
end if
----
set LenDataColumnA to (lastDataRow - firstDataRow) + 1 --takes the large number (from global calculation) and brings it into accuracy, faster than 'length of'
set LenLineColumnA to (lastLineRow - firstLineRow) + 1
set lastBLRow to LenDataColumnA + LenLineColumnA --  the max number of rows expected in the Big List, adjusted later
set endBLRangeCell to rightBLCol & lastBLRow
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Got length 'A' columns..."
	set lastTime to res
end if
----
--  these grab the values in the ranges into variables
set theDataRange to GetTheRanges(DataFileName, DataSheetName, startDataRangeCell, lastDataCol, firstDataRow, lastDataRow)
set theLineRange to GetTheRanges(LineFileName, LineSheetName, startLineRangeCell, lastLineCol, firstLineRow, lastLineRow)
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Move both ranges into variables"
	set lastTime to res
end if
----
set BigList to DoComparisonMerge(theDataRange, DataCompareCol, theLineRange, LineCompareCol)
-- primary handler that does the bulk of the work or farms out to subroutines
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Done parsing data from 2 lists to one Big List..."
	set lastTime to res
end if
----
ProcessResult(BigList) --  sends the result to Excel by row as row length varies, each row sorted by color
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Passing Big List to spreadsheet completed..."
	set lastTime to res
end if
----
SortSheet(BLFileName, BLSheetName, startBLRangeCell, endBLRangeCell, sortBLCol, "BL") -- sorts BL by pn
if DoTimingCheck is true then
	set res to ((timeTools's getMillisec()) - t) / 1000
	log res - lastTime & " Big List worksheet sorted..."
end if
----

--  ==========  this sorts a worksheet into part number ascending order

on SortSheet(XLFileName, XLSheetName, startRangeCell, endRangeCell, XLSortCol, TypeFile)
	tell application "Microsoft Excel"
		tell workbook XLFileName
			tell worksheet XLSheetName
				set UsedRange to used range
				set LastCell to last cell of used range
				set theLastRow to first row index of LastCell
				set theRightCol to ASCII character ((ASCII number ("A")) - 1 + (first column index of LastCell))
				if TypeFile is "Data" then
					set lastDataCol to theRightCol
					set lastDataRow to theLastRow
				else if TypeFile is "Line" then
					set lastLineCol to theRightCol
					set lastLineRow to theLastRow
				else
					set rightBLCol to theRightCol
					set lastBLRow to theLastRow
				end if
				sort UsedRange key1 (range XLSortCol) orientation sort columns order1 sort ascending without header
			end tell
		end tell
	end tell
end SortSheet

--  ==========  get the first colum (part numbers) to use for comparing

on GetFirstCol(XLFileName, XLSheetName, XLSortCol)
	set LineResult1 to {}
	tell application "Microsoft Excel"
		tell workbook XLFileName
			tell worksheet XLSheetName
				set LineResult to the value of range XLSortCol as list --get whole range at once into variable (is a list of 1 item lists)
			end tell --converted from a copy to clipboard command as took 5 seconds
		end tell
	end tell
	repeat with counter1 from 1 to count of LineResult
		set end of LineResult1 to item 1 of (item counter1 of LineResult) -- converts to a list of items
	end repeat
	return LineResult1
end GetFirstCol

--  ========== compare the line versus database info and use this to get data into rows for big list

on DoComparisonMerge(theDataRange, DataCompareCol, theLineRange, LineCompareCol)
	--  now adds rows faster but requires a sort by Excel at the end due to unique Line rows that may come in at randowm
	set ResultingList to {}
	set lengthDataColumn to length of DataCompareCol
	repeat with DataCounter from 1 to lengthDataColumn -- Data A col contents to check vs Line A col
		set DataItem to item DataCounter of my DataCompareCol --take Data pn from left column
		if DataItem ≠ "" then
			if LineCompareCol contains DataItem then -- check shows there is a match, so process with Line data
				set lengthLineColumn to length of LineCompareCol
				set IncludeDataRow to true
				set IncludeLineRow to true
				set theResult to ProcessRows(DataItem, lengthLineColumn, DataCounter, IncludeDataRow, IncludeLineRow, theDataRange, theLineRange, DataCompareCol, LineCompareCol)
			else --   means there is not a match, so save unique data row
				set IncludeDataRow to true
				set IncludeLineRow to false
				set theResult to ProcessRows(DataItem, lengthLineColumn, DataCounter, IncludeDataRow, IncludeLineRow, theDataRange, theLineRange, DataCompareCol, LineCompareCol)
			end if
		end if
		set the end of ResultingList to theResult
	end repeat --  now do the unique Line rows left, if wanted
	if addNewLinePartNumbers is true then --	if the user wants to include unique line part numbers then check to see if there are any
		set lengthLineColumn to length of LineCompareCol
		if lengthLineColumn > 0 then --	means there are some unique line part numbers
			repeat with LineCounter from 1 to lengthLineColumn
				set LineItem to item LineCounter of LineCompareCol
				if LineItem ≠ "" then
					set IncludeDataRow to false
					set IncludeLineRow to true
					set theResult to ProcessRows(LineItem, lengthLineColumn, DataCounter, IncludeDataRow, IncludeLineRow, theDataRange, theLineRange, DataCompareCol, LineCompareCol)
					set the end of ResultingList to theResult
				end if
			end repeat
		end if
	end if
	return ResultingList --the Big List precursor
end DoComparisonMerge

--  ==========   eliminate blanks from a row

on DropBlanks(RowData)
	set RowResult to {}
	repeat with counter1 from 1 to length of RowData
		if item counter1 of RowData ≠ "" then
			set end of RowResult to item counter1 of RowData as string
		end if
	end repeat
	return RowResult -- this Data row has no blanks, including no blanks for status (NEW), which are added later
end DropBlanks

--  ========== compress line row to only cells with color data and associated status

on DoCompresLineRow(RowLine)
	set RowResult to {}
	set end of RowResult to item 1 of RowLine -- the part number
	repeat with counter1 from 2 to length of RowLine by 2
		if item counter1 of RowLine ≠ "" then
			if counter1 + 1 > length of RowLine then
				set LineColorStat to "" -- covers case if the Line row filled cells = length but last cell is color, not status as it was blank
			else
				set LineColorStat to item (counter1 + 1) of RowLine
			end if
			set end of RowResult to item counter1 of RowLine as string
			set end of RowResult to LineColorStat
		end if --  cannot do an exit repeat (after 2 or more blanks) as unsure if there is allowed to be any blankcolor cells in the midst of a row
	end repeat
	return RowResult -- no blank cells for colors, yet there are for status
end DoCompresLineRow

--  ==========  a sort routine based on work from someone else

on SwapSort(tempList) --  by default ignores case, change if you want to use lower case letters in part numbers
	set lengthList to length of tempList
	if lengthList < 2 then return tempList
	set swapDone to true
	repeat while swapDone
		set swapDone to false
		repeat with counter1 from 1 to lengthList - 1
			if item counter1 of tempList > item (counter1 + 1) of tempList then
				set tempSwapItem to item counter1 of tempList
				set item counter1 of tempList to item (counter1 + 1) of tempList
				set item (counter1 + 1) of tempList to tempSwapItem
				set swapDone to true
			end if
		end repeat
		set lengthList to lengthList - 1
	end repeat
	return tempList
end SwapSort

--  ==========  a sort routine based on work from someone else that does the color/status pair at once

on SwapSortPairs(tempList) --  by default ignores case, change if you want to use lower case letters in part numbers
	set lengthList to length of tempList
	if lengthList < 3 then return tempList
	if lengthList mod 2 = 1 then
		set lengthList to lengthList + 1
		set the end of tempList to ""
	end if
	set swapDone to true
	repeat while swapDone
		set swapDone to false
		repeat with counter1 from 1 to (lengthList - 2) by 2
			if item counter1 of tempList > item (counter1 + 2) of tempList then
				set tempSwapColorItem to item counter1 of tempList
				set tempSwapStatusItem to item (counter1 + 1) of tempList
				set item counter1 of tempList to item (counter1 + 2) of tempList
				set item (counter1 + 1) of tempList to item (counter1 + 3) of tempList
				set item (counter1 + 2) of tempList to tempSwapColorItem
				set item (counter1 + 3) of tempList to tempSwapStatusItem
				set swapDone to true
			end if
		end repeat
		set lengthList to lengthList - 2
	end repeat
	return tempList
end SwapSortPairs

--  ========== grab the ranges of cells in one copy action to cut down time

on GetTheRanges(theFileName, theSheetName, startRangeCell, theLastCol, firstRow, lastRow) -- gets whole Data range
	set theRangeList to {}
	tell application "Microsoft Excel"
		tell workbook theFileName
			tell worksheet theSheetName
				set theRangeList to the value of range (startRangeCell & ":" & theLastCol & lastRow) as list
				--gets rid of the copy to clipboard activity, returns a list of lists, each sub-list is a row, commas already in place. perfect.
				return theRangeList
			end tell
		end tell
	end tell
end GetTheRanges

--  ==========  process the selected row for  a match, if data get line match

on ProcessRows(RowItem, lengthLineColumn, DataCounter, DataRowBoolean, LineRowBoolean, theDataRange, theLineRange, DataCompareCol, LineCompareCol) --booleans signify row is included in processing
	if DataRowBoolean is true then --		if this includes processing a data row...
		if item 1 of (item DataCounter of my theDataRange) = RowItem then
			set theDataRow to item DataCounter of my theDataRange --	get the full Data row contents
		end if
		set theDataRow to DropBlanks(theDataRow) -- remove the blanks
		set thePN to item 1 of theDataRow --	the part number
		set colorList to the rest of theDataRow --	the color cells remaining
		set theDataRow to SwapSort(colorList) --	color cells now in order
		set beginning of theDataRow to thePN --	add part number back in
		set theDataRow to InsertStat(theDataRow)
	else
		set theDataRow to "" --	means no data row was included in the processing
	end if
	if LineRowBoolean is true then --	if includes the processing of a line row
		set theLineRowNumber to GetMatchRow(RowItem, lengthLineColumn, LineCompareCol) --  find the Line row
		set theLineRow to item theLineRowNumber of my theLineRange --  get the row's list
		set theLineRow to DoCompresLineRow(theLineRow) -- eliminate any trailing blank cells
		set thePN to item 1 of theLineRow
		set colorList to rest of theLineRow
		set theLineRow to SwapSortPairs(colorList)
		set beginning of theLineRow to thePN
	else
		set theLineRow to "" --	means no line row was processed
	end if
	set theResultRow to MergeRows(theDataRow, theLineRow)
	if sortBLColors is true then --sort row's colors, keeping associated status fields with them
		set thePN to item 1 of theResultRow
		set colorList to rest of theResultRow
		set theResultRow to SwapSortPairs(colorList)
		set beginning of theResultRow to thePN
	end if
	if DataRowBoolean is true then --		if this includes processing a data row...
		set item DataCounter of my theDataRange to ""
		set item DataCounter of DataCompareCol to ""
	end if
	if LineRowBoolean is true then --	if includes the processing of a line row
		set item theLineRowNumber of my theLineRange to ""
		set item theLineRowNumber of LineCompareCol to ""
	end if
	return theResultRow
end ProcessRows

--  ========== this inserts status cells into database records that were not found in line file

on InsertStat(tempList)
	set lengthList to the length of tempList
	if lengthList < 3 then return tempList
	set tempList1 to {}
	set end of tempList1 to item 1 of tempList as string
	set end of tempList1 to item 2 of tempList as string
	repeat with counter1 from 3 to lengthList
		set end of tempList1 to ""
		set end of tempList1 to item counter1 of tempList as string
	end repeat
	set end of tempList1 to ""
	return tempList1
end InsertStat

--  ==========  get the matching line row identity, includes Lion in the Desert trick

on GetMatchRow(RowItem, lengthLineColumn, LineCompareCol) --
	set startPos to 1
	set endPos to lengthLineColumn -- although this does not match the row numbers from Excel, need these as offsets to the start of the list
	repeat
		repeat with LineRowPointer from startPos to endPos
			if RowItem = item LineRowPointer of LineCompareCol then return LineRowPointer
			if RowItem = item endPos of LineCompareCol then return endPos
			if RowItem ≤ item (((endPos - startPos) div 2) + startPos) of LineCompareCol then
				set endPos to ((endPos - startPos) div 2) + 1 + startPos
				set startPos to startPos + 1 -- can increment as we just checked the startPos for a match
				exit repeat
			else
				set startPos to ((endPos - startPos) div 2) + 1 + startPos
				exit repeat
			end if
		end repeat
	end repeat
end GetMatchRow

--  ========== merge the two row lists into one that is sorted, if wanted, by color

on MergeRows(theDataRow, theLineRow)
	set newBLRowList to {}
	if theLineRow ≠ "" then
		set end of newBLRowList to item 1 of theLineRow -- place part number in the new row's list as item 1
	else
		set end of newBLRowList to item 1 of theDataRow -- place part number in the new row's list as item 1
	end if
	if theDataRow ≠ "" then
		set dataColorListing to the rest of theDataRow -- only the data colors are in this list
		set lengthDataColorListing to length of dataColorListing
	else
		set dataColorListing to {} -- no data row
	end if
	if theLineRow ≠ "" then
		set lineColorListing to the rest of theLineRow -- only the line colors (& their status) are in this list
		set lengthLineColorListing to length of lineColorListing -- processes unique color listings from database
	else
		set lineColorListing to {} -- no line row
	end if
	if theDataRow ≠ "" then
		repeat with dataColorPointer from 1 to lengthDataColorListing by 2 --by 2 because it has blank status cell values in list
			if lineColorListing does not contain item dataColorPointer of dataColorListing or theLineRow is "" then -- color unique to database
				set the end of newBLRowList to item dataColorPointer of dataColorListing
				set the end of newBLRowList to "" --  no status associated with database colors, so add a blank cell		
				set item dataColorPointer of dataColorListing to "" -- this color is done so make blank
			end if
		end repeat
	end if
	if theLineRow ≠ "" then
		repeat with lineColorPointer from 1 to lengthLineColorListing by 2 -- processes unique color listings from line
			if dataColorListing does not contain item lineColorPointer of lineColorListing or theDataRow is "" then --this is a color unique to line
				if skipUniqueLineColors is false then -- this means add the unique line color items to the new row
					set the end of newBLRowList to item lineColorPointer of lineColorListing
					if lineColorPointer + 1 > lengthLineColorListing then
						set LineColorStat to "" -- covers case if the Line row filled cells = length but last cell is color, not status as it was blank
					else
						set LineColorStat to item (lineColorPointer + 1) of lineColorListing
					end if
					set the end of newBLRowList to LineColorStat --  add status associated with line color, blank or "NEW"		
				end if
				set item lineColorPointer of lineColorListing to "" -- this color is done so make blank
				if lineColorPointer + 1 ≤ lengthLineColorListing then
					set item (lineColorPointer + 1) of lineColorListing to "" -- this status is done so make blank
				end if
			else -- what remians is the Line colors that are matches of database row colors, so copy line ones with status
				set the end of newBLRowList to item lineColorPointer of lineColorListing
				if lineColorPointer + 1 > lengthLineColorListing then
					set LineColorStat to "" -- covers case if the Line row filled cells = length but last cell is color, not status as it was blank
				else
					set LineColorStat to item (lineColorPointer + 1) of lineColorListing
				end if
				set the end of newBLRowList to LineColorStat --  add status associated with line color, blank or "NEW"		
				set item lineColorPointer of lineColorListing to "" -- this color is done so make blank
				if lineColorPointer + 1 ≤ lengthLineColorListing then
					set item (lineColorPointer + 1) of lineColorListing to "" -- this status is done so make blank
				end if
			end if
		end repeat
	end if
	return newBLRowList
end MergeRows

--  ==========  takes result and sends to Excel by item (which is a list in itself)

on ProcessResult(BigList)
	set LengthBL to length of BigList
	set firstRangeAddrCol to firstBLCol
	repeat with counter1 from 1 to LengthBL
		set BLItem to item counter1 of BigList
		set LengthBLItem to the length of BLItem
		set secondRangeAddrCol to ConvertToASCII(LengthBLItem)
		set destRange to firstRangeAddrCol & currentBLRow & ":" & secondRangeAddrCol & currentBLRow
		InsertValueToRow(destRange, BLItem)
	end repeat
end ProcessResult

--  ========== paste into BL

on InsertValueToRow(destRange, tempList)
	tell application "Microsoft Excel"
		tell workbook BLFileName
			tell worksheet BLSheetName
				set destRange to range (destRange)
				set value of destRange to tempList as list
				set currentBLRow to currentBLRow + 1
			end tell
		end tell
	end tell
end InsertValueToRow

--  ==========  convert numeric to alpha for column identifier

on ConvertToASCII(numericValue)
	set lowerLetterNum to numericValue mod 26
	if lowerLetterNum > 0 then
		set lowerLetterNum to lowerLetterNum - 1
	else
		set lowerLetterNum to 26
	end if
	set lowerLetterAlpha to ASCII character ((ASCII number ("A")) + lowerLetterNum)
	set upperLetterAlpha to ""
	if numericValue > 26 then
		set upperLetterNum to numericValue div 26
		set upperLetterNum to upperLetterNum - 1
		set upperLetterAlpha to ASCII character ((ASCII number ("A")) + upperLetterNum)
	end if
	set AlphaCol to upperLetterAlpha & lowerLetterAlpha
	return AlphaCol
end ConvertToASCII


I just updated the script.
It now runs the same files in about 9 seconds (versus 24 last version).
Changes:

  1. Eliminated any copy to clipboard functions (slow)
  2. Eliminated the set variable to clipboard functions as they were costly time-wise
  3. Streamlined code in the parsing functions
  4. Enabled processing of the data and line information if it is not sorted, although sorting speeds it somewhat
  5. Uses range functions to get and set data in rows or ranges of rows in Excel
  6. Uses ‘used range’ value in Excel to quickly determine size of the range to process and the last (bottom right) cell in the range

I ran into a crash related to the MilliSec routines. I have not looked into it yet but it seems odd. Has to do with the establishing of the value related to the MilliSec processing time.