Merge 2 arrays by key

Hey!!

I have 2 handlers that return data from different sources, while they have one identical (key) parameter.

It is necessary to combine these arrays by the “attrKey” key.

Do you have any ideas how to do it?

Example:

on DataFromSource1()
	set attrKey to "ID"
	set row1 to "Red-"
	set row2 to "Black-"
	
	set attrArray to {}
	set row1Array to {}
	set row2Array to {}
	
	repeat with i from 1 to 3
		set attrKeyNew to attrKey & i
		set end of attrArray to attrKeyNew
		set valuerow1 to row1 & i
		set end of row1Array to valuerow1
		set valuerow2 to row2 & i
		set end of row2Array to valuerow2
	end repeat
	
	return {attrArray, row1Array, row2Array}
end DataFromSource1

on DataFromSource2()
	set attrKey to "ID"
	set row3 to "Green-"
	set row4 to "White-"
	
	set attrArray to {}
	set row3Array to {}
	set row4Array to {}
	
	repeat with i from 1 to 3
		set attrKeyNew to attrKey & i
		set end of attrArray to attrKeyNew
		set valuerow3 to row3 & i
		set end of row3Array to valuerow3
		set valuerow4 to row4 & i
		set end of row4Array to valuerow4
	end repeat
	
	return {attrArray, row3Array, row4Array}
end DataFromSource2

Show the example input and output you wish to get.

1 Like

Agreed. We seem to have example input data, but your terminology is confusing. Neither of those sample data sources return actual “keys” connected to data. A more accurate description of your sample input would be that each data source returns an array of arrays, where the “key” for a piece of info is just the matching-index value in the 1st array.
So, that makes it unclear what you would want the output to be.
Should it be an array of arrays where the 1st sub-array is an array of the “ID” values, with the other arrays just all tacked into the overall array?
Or, should it be an array of arrays nested together some other way?
Or, do you want an array of records (AppleScript’s closest-equivalent to an associative array)? Those would have named key/value pairs, looking something like this:
{{ID:"ID1", Comp:"Comp1", Monitor:"Monitor1", Serial:"Serial1", Inventory:"Inventory1"}, {ID:"ID2", Comp:"Comp2", Monitor:"Monitor2", Serial:"Serial2", Inventory:"Inventory2"},…}

Of course, what you want to use that final data structure for should be considered when deciding what format you want it to be in. So, how do you plan to use the combined result?

@Krioni, I didn’t change the script much in the first message… values can be any.

The main thing at the output is to get combined arrays.

The result should be as follows:

{{“ID1”, “Red-1”, “Black-1”, “Green-1”, “White-1”}, {“ID2”, “Red-2”, “Black-2”, “Green-2”, “White-2”}, {“ID3”, “Red-3”, “Black-3”, “Green-3”, “White-3”}}

Ok. Some terminology suggestions: in AppleScript, an “array” is called a “list”.
So, let’s clarify what you are trying to accomplish:
You have two lists of lists, ListA and ListB.
In each of those lists, the first sub-list’s items will be used as the “match value” (let’s avoid using “key”, since that could cause confusion).
You want the output to be as follows:
A list of lists, where each sub-list starts with the “match value” (“ID”) followed by all the other same-index values from the other input sub-lists.
Is that correct? One thing I wonder: is the attrArray always the same, index-wise? In other words, your sample input has {“ID1”, “ID2”, “ID3”} for both sources. Is it possible that source #2 might instead be {“ID1”, “ID3”, “ID4”} (skipping ID2)?
If the sub-lists are always all the same length and IDs, the loop that combines the sub-lists can be very simple. If it does need to do an actual match (per source), that’s a bit more work, since you need a “Get Index of Value in List” function, which folks have made and use, in order to know which items to extract from the other sub-lists for that source

@Krioni, No, there can be no passes. The ID of one list always coincides with another.

Well, here is code that will work with your example data. This may not be the best way to handle this, but the appendToSubList function I made that is included here does the bulk of the work.



-- DESIRED OUTPUT: 
--{{"ID1", "Red-1", "Black-1", "Green-1", "White-1"}, {"ID2", "Red-2", "Black-2", "Green-2", "White-2"}, {"ID3", "Red-3", "Black-3", "Green-3", "White-3"}}

set outputList to {}

set {attrArray, row1Array, row2Array} to DataFromSource1()
-- SAMPLE: {{"ID1", "ID2", "ID3"}, {"Red-1", "Red-2", "Red-3"}, {"Black-1", "Black-2", "Black-3"}}

set itemCount to length of attrArray

appendToSubList(outputList, attrArray)
appendToSubList(outputList, row1Array)
appendToSubList(outputList, row2Array)


set {attrArray, row1Array, row2Array} to DataFromSource2()
-- SAMPLE: {{"ID1", "ID2", "ID3"}, {"Green-1", "Green-2", "Green-3"}, {"White-1", "White-2", "White-3"}}

appendToSubList(outputList, row1Array)
appendToSubList(outputList, row2Array)

return outputList


on appendToSubList(nestedList, subList)
	-- Where nestedList is a list of lists (or should be!), takes each item from subList and appends it to the matching-index sub-list in nestedList.
	-- If the sublist does not yet exist in nestedList, create it.
	
	repeat with i from 1 to length of subList
		set oneItem to item i of subList
		if length of nestedList is less than i then copy {} to end of nestedList
		copy oneItem to end of item i of nestedList
	end repeat
	
	return nestedList
	
end appendToSubList



on DataFromSource1()
	set attrKey to "ID"
	set row1 to "Red-"
	set row2 to "Black-"
	
	set attrArray to {}
	set row1Array to {}
	set row2Array to {}
	
	repeat with i from 1 to 3
		set attrKeyNew to attrKey & i
		set end of attrArray to attrKeyNew
		set valuerow1 to row1 & i
		set end of row1Array to valuerow1
		set valuerow2 to row2 & i
		set end of row2Array to valuerow2
	end repeat
	
	return {attrArray, row1Array, row2Array}
end DataFromSource1

on DataFromSource2()
	set attrKey to "ID"
	set row3 to "Green-"
	set row4 to "White-"
	
	set attrArray to {}
	set row3Array to {}
	set row4Array to {}
	
	repeat with i from 1 to 3
		set attrKeyNew to attrKey & i
		set end of attrArray to attrKeyNew
		set valuerow3 to row3 & i
		set end of row3Array to valuerow3
		set valuerow4 to row4 & i
		set end of row4Array to valuerow4
	end repeat
	
	return {attrArray, row3Array, row4Array}
end DataFromSource2
1 Like

@Krioni, It’s magic!!
It looks simple and really works!

Thank you! I checked it on the main script and it seems to work as it should. I will test it more during the day.


Although no, I was in a hurry, here the lists will simply be merged, without taking into account the key.
The key should probably be an index, or something like that.

I’ll still have to think about it.

Glad that is working for you!
In case this matters for your situation: for long lists, that appendToSubList handler probably isn’t the fastest way to do this. There are other posts here at MacScripter.net about optimized methods of appending to long lists.

I changed the output of the handlers, and as a result, I managed to merge these lists.

set array1 to {{"Red-1", "Black-1", "ID1"}, {"Red-2", "Black-2", "ID2"}}
set array2 to {{"Green-1", "White-1", "ID1"}, {"Red-2", "Black-2", "ID2"}}


MergeLists(array1, array2)
--result
--{{"Red-1", "Green-1", "White-1", "Black-1", "ID1"}, {"Red-2", "Red-2", "Black-2", "Black-2", "ID2"}}

on MergeLists(List1, List2)
	set MergeLists to {}
	
	repeat with subList1 in List1

		set {Value01, Value02, ID01} to subList1
		
		repeat with subList2 in List2
			set {Value11, Value12, ID11} to subList2
			if ID01 is equal to ID11 then
				set end of MergeLists to {Value01, Value11, Value12, Value02, ID01}
				exit repeat
			end if
		end repeat
	end repeat
	
	return MergeLists

end MergeLists