How do I convert a string of numbers from text to a list if integers?

(*list of integers, sorry)

Basically, I need to accomplish the following: “1, 2, 3, 4, 5” → {1, 2, 3, 4, 5}

I do NOT want this: {“1”, "2, “3”, “4”, “5”}
…and I definitely do NOT want this: {“1”, ", ", “2”, ", " “3”, ", ", “4” ", ", “5”}

For some reason, the following doesn’t work properly when copied into this site, but here’s a part of what it is I’m trying to do:

set question to display dialog "Enter number of trials:" default answer "1000"
set trials to (text returned of question)

set choice_wolfram to "\"http://api.wolframalpha.com/v2/query?appid=UERAH9-KW3Y2UHXE8&input=" & trials & "%20random%20integers%20between%201%20and%203" & "&format=plaintext\""

set choice_output to do shell script "curl " & choice_wolfram
set first_choice to text ((offset of "<subpod title=''
      primary='true'>
   <plaintext>{" in choice_output) + 54) thru ((offset of "<subpod title=''
      primary='true'>
   <plaintext>{" in choice_output) + ((54 + (trials * 3)) - 3)) of choice_output

…here’s the whole thing: https://dl.dropboxusercontent.com/u/14131544/The%20Monty%20Hall%20Problem%20(WolframAlpha).scpt

But it’s a useful first step:

set x to "1, 2, 3, 4, 5"
set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set theList to text items of x
set AppleScript's text item delimiters to saveTID
repeat with i from 1 to count of theList
	set item i of theList to (item i of theList as integer)
end repeat

You could also use the more hack-ish:

set x to "1, 2, 3, 4, 5"
set theList to run script ("{" & x & "}")

It’s a lot shorter, but takes a lot longer to run.

Thank you! The script works perfectly with that! I was a bit worried about adding more repeats to this, but if that really is the only work around for this, it doesn’t seem to add too much extra time to the calculation… So again, thank you!

it depends a bit on how long your lists are. For very long lists, the run script method is probably quicker.

Hello.

This works for natural numbers including zero, just as an alternative, I have no idea if it is any faster, or anything, just that it won’t accept decimal numbers (at least not with my decimal separator which is “,”) and negative whole numbers (everywhere). It is here for terseness.

set l to {}
tell (a reference to words of "1, 3 , 2, 3, 4, -5")
	repeat with i from 1 to (count of it)
		set end of l to item i of it as number
	end repeat
end tell

I sat down to test these methods and even with the shortest list I’d use in my script (100 data points) that method was only ever 1 second longer than the other… at most. The difference only went down from there, so I’ll be using the shorter method.

Hello

To test its speed, I tried to run the version :

Open this Scriplet in your Editor:
set x to "1, 2, 3, 4, 5"
set theList to run script ("{" & x & "}")

with a string of 31291 bytes.

I got :
→ error “« , » ou « } » prévu mais jeton inconnu trouvé.” number -2741

Is the string too long for an object script ?

Yvan KOENIG (VALLAURIS, France) vendredi 29 novembre 2013 17:34:29

It was not that. The numbers were formatted the French way with a no break space used as thousand separator.
When I used numbers without this separator, the script did its duty (4440 numbers of 4/5 digits) in less than one second.

Ok… more testing: The run script method is by far the fastest of the two Shane provided, but I get a stack overflow after 8078 items. I personally don’t mind it, but is there a way to remove this limit and keep the fast conversion time?

set x to "1"
repeat 8077 times
	set x to x & ", 1"
end repeat

say (count words of x) using "Alex" speaking rate 220 pitch 10 modulation 70

say "Delimiter method:" using "Alex" speaking rate 220 pitch 10 modulation 70
set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set theList to text items of x
set AppleScript's text item delimiters to saveTID
repeat with i from 1 to count of theList
	set item i of theList to (item i of theList as integer)
end repeat
say "complete" using "Alex" speaking rate 220 pitch 10 modulation 70

delay 1

say "Run script method:" using "Alex" speaking rate 220 pitch 10 modulation 70
set theList to run script ("{" & x & "}")
say "complete" using "Alex" speaking rate 220 pitch 10 modulation 70

set x to x & ", 1"

delay 1

say (count words of x) using "Alex" speaking rate 220 pitch 10 modulation 70

say "Delimiter method:" using "Alex" speaking rate 220 pitch 10 modulation 70
set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set theList to text items of x
set AppleScript's text item delimiters to saveTID
repeat with i from 1 to count of theList
	set item i of theList to (item i of theList as integer)
end repeat
say "complete" using "Alex" speaking rate 220 pitch 10 modulation 70

delay 1

say "Run script method:" using "Alex" speaking rate 220 pitch 10 modulation 70
set theList to run script ("{" & x & "}")
say "complete" using "Alex" speaking rate 220 pitch 10 modulation 70

Hello.

You can’t address more than 2^14 elements. I don’t think there is a cure although I haven’t tested having several script objects in one main script, each containing a list of say 2^14 prime numbers. :slight_smile:

An faster version of Shane by using references.


set x to "1, 2, 3, 4, 5"

script o
	property lst : {}
end script

set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set o's lst to text items of x
set AppleScript's text item delimiters to saveTID

repeat with i from 1 to count o's lst
	set item i of o's lst to (item i of o's lst as integer)
end repeat

return o's lst

Even with lists up to 1200 items it’s better to use the method above (I didn’t test larger files).

edit: and support larger lists :slight_smile:

Hello.

Just for the record, my solution in post #5 also uses references, and should be quite fast, since the string literal is turned into a reference to list a of words when it starts to convert the list into positive integers.

The same caveat about positive integers still holds however, so for maximum flexibility unless you aren’t dealing with primenumbers etc, then the script above is better when you have to work around the constraint that you have reached.

You also may try to split it into two lists of course, if that is practical, before you use the run script to convert the strings of numbers into lists. :slight_smile:

Ok, testing…

set x to "1"
repeat 4 times
	set x to x & ", 1"
end repeat

say ((count words of x) as text) & " items:" using "Alex" speaking rate 220 pitch 10 modulation 70

script o
	property lst : {}
end script

set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set o's lst to text items of x
set AppleScript's text item delimiters to saveTID

repeat with i from 1 to count o's lst
	set item i of o's lst to (item i of o's lst as integer)
end repeat

say "completed" using "Alex" speaking rate 220 pitch 10 modulation 70

delay 1

repeat 9995 times
	set x to x & ", 1"
end repeat

say ((count words of x) as text) & " items:" using "Alex" speaking rate 220 pitch 10 modulation 70

set saveTID to AppleScript's text item delimiters
set AppleScript's text item delimiters to {","}
set o's lst to text items of x
set AppleScript's text item delimiters to saveTID

repeat with i from 1 to count o's lst
	set item i of o's lst to (item i of o's lst as integer)
end repeat

say "completed" using "Alex" speaking rate 220 pitch 10 modulation 70

I’m happy! :smiley:

If you want to turn negative numbers into positive numbers you should still use:

set x to read file ((path to desktop folder as string) & "testnumbers.txt")

script o
	property lst : {}
end script

set o's lst to words of x

repeat with i from 1 to count o's lst
	set item i of o's lst to (item i of o's lst as integer)
end repeat

return o's lst

The script in post #5 hangs with an list of 7000 items (showing beach ball after 1 minute) while this version still does it in less than a second. The difference in code relies only in creating an list of strings, this version just ignores any kind of punctuation including the hyphen.

Than we’re happy :slight_smile:

:frowning: Not so happy. I timed my version just for the hell of it, and discovered, that that kind of reference didn’t quite work as a reference to a property in a script object. And I don’t even get a beach ball! :slight_smile:

I agree fully to the sentiment about negative numbers, that is why I stated that the “word” version only worked with positive, since any dashes gets filtered out as it is not reckognized as a word character.:slight_smile:

If you’re talking large numbers, an ASObjC library is a good alternative:

use framework "Foundation"
on intsFromString:y
	set aString to current application's NSString's stringWithString:y
	return ((aString's componentsSeparatedByString:",")'s valueForKey:"intValue") as list
end intsFromString:

OMM, the difference for 1000 items is 0.004 seconds vs 0.042 seconds. But it’s probably going to be slower for fewer than about 40 items.

Just in case if anyone wants to create the random list by itself instead of grabbing from an webservice:


createRandomList(1, 45, 10000)

on createRandomList(f, t, s)
	script o
		property orderedNumbers : {}
		property randomNumbers : {}
	end script
	
	repeat with x from f to t
		set end of o's orderedNumbers to x
	end repeat
	
	repeat s times
		set end of o's randomNumbers to some item of o's orderedNumbers
	end repeat
	return o's randomNumbers
end createRandomList

That was mostly me just playing with the WolframAlpha api, but yeah… using AppleScript to generate the list does simplify things a bit further.
The link in my original post uses WolframAlpha, but I’ll use AppleScript from now on.

This is pretty much near final:

set pool to 1000
set trial to 1
set trials to ""

on createRandomList(f, t, s)
	script o
		property orderedNumbers : {}
		property randomNumbers : {}
	end script
	
	repeat with x from f to t
		set end of o's orderedNumbers to x
	end repeat
	
	repeat s times
		set end of o's randomNumbers to some item of o's orderedNumbers
	end repeat
	return o's randomNumbers
end createRandomList

script o
	property lst : {}
end script



repeat
	
	set question to display dialog "Enter size of data pool:" with title "The Monty Hall Problem" default answer pool
	set pool to (text returned of question)
	
	
	set first_choice to createRandomList(1, 3, pool)
	
	set the_car to createRandomList(1, 3, pool)
	
	set the_goat to createRandomList(1, 2, pool)
	
	
	set final_choice to {}
	set choice_tf to {}
	set choice_true to ""
	
	repeat with x from 1 to pool
		
		if item x of first_choice is equal to 3 then
			
			if item x of the_car is equal to 1 then set item x of the_goat to 2
			if item x of the_car is equal to 2 then set item x of the_goat to 1
			
			if item x of the_goat is equal to 1 then set final_choice to final_choice & 2
			if item x of the_goat is equal to 2 then set final_choice to final_choice & 1
			
		end if
		
		if item x of first_choice is equal to 1 then
			if item x of first_choice is equal to item x of the_car then set item x of the_goat to (item x of the_goat) + 1
			if item x of the_car is equal to 2 then set item x of the_goat to 3
			if item x of the_car is equal to 3 then set item x of the_goat to 2
			
			if item x of the_goat is equal to 2 then set final_choice to final_choice & 3
			if item x of the_goat is equal to 3 then set final_choice to final_choice & 2
			
		end if
		
		if item x of first_choice is equal to 2 then
			if item x of first_choice is equal to item x of the_car then
				if item x of the_goat is equal to 2 then set item x of the_goat to 3
			end if
			
			if item x of the_car is equal to 1 then set item x of the_goat to 3
			if item x of the_car is equal to 3 then set item x of the_goat to 1
			
			if item x of the_goat is equal to 1 then set final_choice to final_choice & 3
			if item x of the_goat is equal to 3 then set final_choice to final_choice & 1
			
		end if
		
		if item x of final_choice is equal to item x of the_car then
			set choice_tf to choice_tf & true
			set choice_true to choice_true + 1
		else
			set choice_tf to choice_tf & false
		end if
		
	end repeat
	
	
	
	set percent to ((choice_true * 100) / pool)
	
	set final_output to (trial as text) & ": " & "Switching wins " & choice_true & " out of " & pool & ", or " & percent & "%."
	
	set dialog_text to trials & final_output
	
	set question to display dialog dialog_text with title "The Monty Hall Problem" buttons {"Quit", "Run another trial"} default button 2
	
	if button returned of question is equal to "Quit" then
		error number -128
	else
		set trials to trials & final_output & "
"
		set trial to trial + 1
		
	end if
	
end repeat