Faster Search/Replace In Numbers Columns

I have this simple script that searches/replaces text values in a column, and it works fine. However, it takes a significant amount of time to run for even only a few thousand cells.

Is there anything I can do to speed up that process? For example, is there any way to invoke the native search/replace function within Numbers that does the same thing in mere seconds instead of literally going from cell to cell all the way down, or is there a better way to script this?

repeat with x in column "H"'s cells
	tell x to if its value contains "in" then set its value to "Incoming"
	tell x to if its value contains "out" then set its value to "Outgoing"
end repeat

 

tell application "Numbers" to tell table 1 of sheet 1 of document 1
	set inCells to a reference to (cells of column "H" whose value contains "in")
	set outCells to a reference to (cells of column "H" whose value contains "out")
	set value of inCells to "Incomming"
	set value of outCells to "Outgoing"
end tell

 

Thanks for that, and it definitely runs faster, but still taking 1:32 for each file, of which I have hundreds. Any other ideas you might have to cut down that time further, or is the physical cell iteration process, one by one, unavoidable?

That script is not iterating „one by one“. It gets all matching cells in two lists and then updates these. I don’t know if a faster solution is possible with AppleScript.

Well that explains why it’s faster than my version, but it’s quite amazing that it still takes this long when the same process natively in Numbers takes 2 seconds!

Would it make any difference if some of the cells were blank, meaning to say, that it skipped those cells when creating the lists?

I was hoping that would improve the timing but it’s the same as before. I noticed that the entire delay is due to the “Spreadsheet updating” that shows the cells in gray and puts the cursor in busy mode, and assumed your code to ignore the application responses would deal with that, but i guess not.

How many rows do you have per column? The fact is that the command WHOSE with a certain large number of rows starts to “slow down”. The repeat loop inside the tell block is even worse.

It is better to break the work with rows into several pieces. The speed should improve. Here is an example of working with 2 pieces:

 

tell application "Numbers" to tell table 1 of sheet 1 of document 1
	
	set value of cells of range "H1:H200" whose value contains "in" to "Incomming"
	set value of cells of range "H1:H200" whose value contains "out" to "Outgoing"
	
	set value of cells of range "H201:H400" whose value contains "in" to "Incomming"
	set value of cells of range "H201:H400" whose value contains "out" to "Outgoing"
	
end tell

 

6000 rows, I’ll try that and report back.

So here is what I used and it was a MASSIVE improvement, going from 1:55 to only :20. So that’s awesome. Question is, I noticed you used this code instead of the prior one below where you loaded the range into a variable. Should I try that as well broken up?

set (value of cells of range "H1:H1000" whose value contains "in") to "Incomming"
set (value of cells of range "H1:H1000" whose value contains "out") to "Outgoing"
			
set (value of cells of range "H1001:H2000" whose value contains "in") to "Incomming"
set (value of cells of range "H1001:H2000" whose value contains "out") to "Outgoing"
			
set (value of cells of range "H2001:H3000" whose value contains "in") to "Incomming"
set (value of cells of range "H2001:H3000" whose value contains "out") to "Outgoing"
			
set (value of cells of range "H3001:H4000" whose value contains "in") to "Incomming"
set (value of cells of range "H3001:H4000" whose value contains "out") to "Outgoing"
			
set (value of cells of range "H4001:H5000" whose value contains "in") to "Incomming"
set (value of cells of range "H4001:H5000" whose value contains "out") to "Outgoing"
			
set (value of cells of range "H5001:H6000" whose value contains "in") to "Incomming"
set (value of cells of range "H5001:H6000" whose value contains "out") to "Outgoing"


		
set inCells to a reference to (cells of column "H" whose value contains "in")
set outCells to a reference to (cells of column "H" whose value contains "out")
set value of inCells to "Ingoing"
set value of outCells to "Outgoing"

Also, the other issue is that each spreadsheet has a different number of rows, so can you modify this to dynamically split the known number of rows into smaller chunks, with a variable set to the chunk number so that I can then control it without having individually change the actual row ranges, which I would never know in advance?

I would envision the chunk number not being an actual number of rows per se, but the number of breakouts, so that in this case that number would be 6.

 

tell application "Numbers" to tell table 1 of sheet 1 of document 1
	
	set piece to 1000
	set rowCount to row count
	set C to 0
	
	repeat
		try
			set R to C + 1
			set C to C + piece
			set RC to "H" & R & ":H" & C -- the next range
			set value of cells of range RC whose value contains "in" to "Incomming"
			set value of cells of range RC whose value contains "out" to "Outgoing"
			if C = rowCount then exit repeat
		on error
			set RC to "H" & R & ":H" & rowCount -- the rest range
			set value of cells of range RC whose value contains "in" to "Incomming"
			set value of cells of range RC whose value contains "out" to "Outgoing"
			exit repeat
		end try
	end repeat
	
end tell

 

This works awesome - turns out it’s even faster than before for some reason. Can you explain why you have the “on error” section of the code?

The script processes per 1000 rows. Let’s say you have 6200 lines. Then you should have for the last piece: 6001-6200.

The normal part of the TRY-block gives 6001-7000 for the 7th piece. Since there is no such range (>6200), an error is thrown. This error is caught by the ON ERROR part of the TRY block and fixes 6001-7000 to 6001-6200.

Brilliant! Thanks so much for your invaluable help!

If you have a moment to look at my other two posts that I need help with, that would be great!

https://www.macscripter.net/t/format-telephone-number-in-numbers/74769/2

https://www.macscripter.net/t/using-applescript-to-set-alternating-row-color/74771

Hi.

This is quite fast in with Numbers 10.1 in Mojave:

on main()
	script o
		property allValues : missing value
	end script
	
	tell application "Numbers"
		activate
		tell table 1 of sheet 1 of document 1
			set rowCount to row count
			-- Select the whole of column H and get its values.
			set selection range to range ("H1:H" & rowCount)
			set o's allValues to value of cells of selection range
		end tell
	end tell
	
	-- Edit the values in-script.
	repeat with r from 1 to rowCount
		set this to o's allValues's item r
		if (this contains "in") then
			set o's allValues's item r to "Incoming"
		else if (this contains "out") then
			set o's allValues's item r to "Outgoing"
		else if (this is missing value) then
			set o's allValues's item r to ""
		end if
	end repeat
	
	-- Coerce the list to text with linefeed delimiters and send it to the clipboard.
	set the clipboard to join(o's allValues, linefeed)
	
	-- Paste the result into the selected Numbers column.
	tell application "System Events"
		set frontmost of application process "Numbers" to true -- Probably overkill.
		keystroke "v" using {shift down, option down, command down}
	end tell
end main

on join(lst, delim)
	set astid to AppleScript's text item delimiters
	set AppleScript's text item delimiters to delim
	set txt to lst as text
	set AppleScript's text item delimiters to astid
	return txt
end join

main()

Not sure how to incorporate that into a working script for the open document. As it is here, it does not run. Thanks.

Well. It won’t do anything if you leave out the last line, of course. :slight_smile: Apart from that, the assumptions are that you want to change values in column “H” of table 1 of sheet 1 of document 1 (as in KniazidisR’s scripts, which appear to work for you), that Numbers scripting is broadly similar on both our systems, and that GUI scripting is enabled on yours.

I don’t think GUI is enabled on mine, where do I do that on my mac?

So I circled back here to try your script on the search/replace, and I now have GUI enabled but when the try to run it, nothing happens. I press the arrow and there’s no error or anything, but it doesn’t say the script is running or anything. What could I be doing wrong?