Adding Numbers To List

I’m hugely embarassed that I haven’t got a clue how to do this…

I have a simple list of numbers, and want to insert additional numbers in the list in strict sequence:

e.g.

set _list to {2, 5, 9}

–set new_list_entry to 1 – Example A
–set new_list_entry to 6 – Example B

… and of course I’d like the result to be:

Example A: {1, 2, 5, 9}
Example B: {2, 5, 6, 9}

I’ve tried a few repeat loops involving if < or > then, and I made a (perfunctory) search of the forum, but can’t seem to wrap my head around this very simple logic.

(Don’t blame it on the turkey, I had Kung Pao Pork tonight.)

If someone would oblige, vanilla AS in terms I can understand is preferred.

Thanks Much.

Peter B.


Hi Peter,
This was harder than I thought also. I’m still testing my code below but maybe you can run some tests and see if it works for you. Some of the cleverer guys may have a better solution but please give this a try for now!

set no_list to {2, 5, 9}

set new_list_entry to 3 -- Example A
--set new_list_entry to 6 -- Example B


repeat with i from 1 to the number of items of no_list
	set this_no to item i of no_list
	if new_list_entry < this_no then
		set list_position to i
		exit repeat
	end if
end repeat

set new_list to {}
repeat with i from 1 to the number of items of no_list
	set this_no to item i of no_list
	if i = list_position then
		set this_no to new_list_entry & this_no
	else
		set this_no to this_no
	end if
	set new_list to new_list & this_no
end repeat

choose from list new_list

Nik

Hi,

try this

set no_list to {2, 5, 9}

set new_list_entry to 7 -- Example A
--set new_list_entry to 10 -- Example B

choose from list insert_list_item(no_list, new_list_entry)

on insert_list_item(L, newItem)
	if newItem is in L then
		return L -- doesn't insert, if the value is alread in the list
	else if newItem < item 1 of L then
		return newItem & L
	else
		repeat with i from 2 to count L
			if newItem < item i of L then return (items 1 thru (i - 1) of L) & newItem & (items i thru -1 of L)
		end repeat
		
		if newItem > last item of L then
			return L & newItem
		else
			return (items 1 thru -2 of L) & newItem & last item of L
		end if
	end if
end insert_list_item

I think I’d just go for appending and sorting:

set oldList to {2, 5, 9}
set addNum to {1, 6}
set NL to {} 

repeat with N in addNum
	set NL's end to sort(oldList & N)
end repeat

NL --> {{1, 2, 5, 9}, {2, 5, 6, 9}}

to sort(sortList)
	script L
		property srt : sortList
	end script
	tell (count L's srt) to repeat with i from (it - 1) to 1 by -1
		set s to (L's srt)'s item i
		repeat with i from (i + 1) to it
			tell (L's srt)'s item i to if s > it then
				set (L's srt)'s item (i - 1) to it
			else
				set (L's srt)'s item (i - 1) to s
				exit repeat
			end if
		end repeat
		if it is i and s > (L's srt)'s end then
			set (L's srt)'s item it to s
		end if
	end repeat
	return L's srt
end sort

blend3, StefanK and Adam Bell:

Thank you all very much for the examples… I should be able to adapt one or the other to work.

The example I provided was in simplest possible form. I will need to work with numbers higher than 10, so StefanK’s solution (and the nice added feature of excluding existing numbers) looks like it might work better for me.

I will probably only be adding one number at a time to an existing list, so Adam’s ‘append and sort’ may not be necessary… but you never know.

I have multiple tab delimited text files of an auto parts inventory with hundreds of existing entries to which I’d like to add more… in proper sequence. Your help should make that possible. I hope I can work out the rest of the needed details… but I’ve never done much scripting with lists, and trying to work out the insertion would have beaten me to death… literally.

Thanks Again.

Peter B.


If you’re dealing with lists that must be kept in correspondence (that is a sort of several based on an insertion in one must keep the others in the same order) there are neat ways of doing that.

I should be paying for this…

I was dead wrong. Even with the examples provided this morning, I still can’t put this all together on my own. The finer details have stumped me too.

I hope it’s clear from the code and comments below what I’m trying to do.

(StefanK: You may recognize your handler at the end of my own mess. Now that I think of it, replacing an existing entry might actually be useful when {e.g.} a quantity or a price change occurs.)

I’m getting closer, anyway… up next is the ‘front end’.

Thanks.

Peter B.




tell application "Finder"
	
	set new_entry to "0418043	2.75	2	$5.50"
	--set new_entry to "0418078	3.50	4	$14.00"
	
	set new_entry_value to word 1 of new_entry as number
	
	set read_data to "0418044	2.49	1	$2.49
0418045	2.47	2	$4.94
0418055	2.25	15	$33.75
0418058	3.21	1	$3.21
0418063	2.61	1	$2.61
0418065	4.28	1	$4.28
0418066	2.10	15	$31.50
0418068	5.40	1	$5.40
0418069	2.98	1	$2.98
0418072	2.75	1	$2.75
0418074	2.19	15	$32.85
0418075	2.52	5	$12.60"
	
	set entry_values to {}
	
	repeat with paragraph_n in paragraphs of read_data
		set entry_value to word 1 of paragraph_n as number
		set entry_values to ((entry_values) & entry_value) as list
	end repeat
	
	set numeric_inventory to my insert_list_item(entry_values, new_entry_value)
	
	-----
	
	--Begin pseudo code... a failed shot in the dark...
	
	-- The object here is to replicate format of read_data with complete new entry paragraphs included... *without* multiple duplication of existing entries...
	
	set inventory_output to ""
	
	repeat with this_value in numeric_inventory
		if this_value is in read_data then
			repeat with paragraph_n in paragraphs of read_data
				set inventory_output to inventory_output & paragraph_n & return
			end repeat
		else
			set inventory_output to inventory_output & new_entry & return
		end if
	end repeat
	
	--End pseudo code...
	
	-----
	
	set amended_inventory to (desktop as text) & "Amended Inventory.txt"
	
	try
		open for access file amended_inventory with write permission
		set eof of file amended_inventory to 0
		write inventory_output to file amended_inventory starting at eof
		close access file amended_inventory
	on error
		close access file amended_inventory
	end try
	
	open file amended_inventory
	
end tell

-----

on insert_list_item(entry_values, new_entry_value)
	if new_entry_value is in entry_values then
		return entry_values -- doesn't insert, if the value is already in the list
	else if new_entry_value < item 1 of entry_values then
		return new_entry_value & entry_values
	else
		repeat with i from 2 to count of entry_values
			if new_entry_value < item i of entry_values then return (items 1 thru (i - 1) of entry_values) & new_entry_value & (items i thru -1 of entry_values)
		end repeat
		
		if new_entry_value > last item of entry_values then
			return entry_values & new_entry_value
		else
			return (items 1 thru -2 of entry_values) & new_entry_value & last item of entry_values
		end if
	end if
end insert_list_item

-----


I guess I don’t understand, Peter.

  1. You have an existing text list that is both tab and return delimited (spreadsheet?)

  2. You want to add a new line. In your workflow, how will you choose the number? You could choose from alist showing all the missing numbers in the existing list.

set read_data to "0418044		2.49	1	$2.49
0418045	2.47	2	$4.94
0418055	2.25	15	$33.75
0418058	3.21	1	$3.21
0418063	2.61	1	$2.61
0418065	4.28	1	$4.28
0418066	2.10	15	$31.50
0418068	5.40	1	$5.40
0418069	2.98	1	$2.98
0418072	2.75	1	$2.75
0418074	2.19	15	$32.85
0418075	2.52	5	$12.60"

set rdList to paragraphs of read_data

set nums to {}
repeat with N in rdList
	set end of nums to (word 1 of N) as number
end repeat

-- assuming the numbers are in order (sorted) then
set wee to item 1 of nums
set big to item -1 of nums
set available to {}

repeat with k from wee + 1 to big - 1
	if k is not in nums then set available's end to "0" & k
end repeat
--> the list of missing numbers
  1. If the number picked without benefit of the available numbers and is already in the list, the best thing would be to choose one nearby if position in the list means anything. Otherwise why not just add it to the end or beginning?

  2. The way to deal with reconstructing the tab/return text list is to do it by insertion in the AppleScript list and then use text item delimiters to reconstruct the paragraphs.

to insertInList(myList, Insertion, AfterNum)
	if AfterNum ≥ (count of myList) then
		set end of myList to Insertion
		return myList
	end if
	tell myList
		set frontPart to items 1 thru AfterNum
		set backPart to items (AfterNum + 1) thru -1
	end tell
	set myList to frontPart & Insertion & backPart
	return myList
end insertInList

Adam:

Thanks again… yes, the existing inventory is in text form… as exported from a Windows Excel spreadsheet.

I may be approaching the problem in the wrong way… and maybe asking about it in the wrong way as well. In my last script example, the two new sample entries were carelessly selected… as needing to be added at the beginning or the end of the existing list.

I will also need to add entries that are between numeric values in the list:

set new_list_entry to “0418047 1.05 2 $2.10”

set existing_list to “0418044 2.49 1 $2.49
0418045 2.47 2 $4.94
0418055 2.25 15 $33.75
0418058 3.21 1 $3.21”

… so that the resultant list becomes:

0418044 2.49 1 $2.49
0418045 2.47 2 $4.94
0418047 1.05 2 $2.10
0418055 2.25 15 $33.75
0418058 3.21 1 $3.21

The ‘front end’ for new entries I already have working…

(I hesitate to add this because it may only confuse the issue further. Each set of new entry values are entered in an HTML form, then passed to a target script {the one I’m working on} via Missing Link.)

The target script parses out the values and sets them in tab delimited form:

set inventory_addition to part_num & tab & unit_cost & tab & stock_quan & tab & exten_value

… to create a new paragraph.

In the actual script, data is read in from the existing inventory list. I then need to insert the new paragraph entry into the list… in numeric sequence by part number. That’s the only remaining problem.

(The amended inventory is then spit out to a new file.)

StefanK’s script allowed me to insert a simple numeric value in an existing list of values and I thought I could take that result and make the full paragraphs of the list ‘follow suit’, as it were. But I’m still (obviously) struggling with that bit.

I guess I should spend some more time studying the examples I’ve already been given… maybe a light will finally go on.

If it ever does, I’ll post the final script.

Peter B.


A half an hour later… light in the forest !!!

Convoluted as it may be, I should be able to work with this.

Thanks again for all the help here. I’m very pleased.

Onnerds and upperds.

Peter B.



global read_data
global new_entry

tell application "Finder"
	
	--set new_entry to "0418043	2.75	2	$5.50"
	set new_entry to "0418073	.45	8	$3.60"
	--set new_entry to "0418078	3.50	4	$14.00"
	
	set new_entry_value to word 1 of new_entry as number
	
	set read_data to "0418044	2.49	1	$2.49
0418045	2.47	2	$4.94
0418055	2.25	15	$33.75
0418058	3.21	1	$3.21
0418063	2.61	1	$2.61
0418065	4.28	1	$4.28
0418066	2.10	15	$31.50
0418068	5.40	1	$5.40
0418069	2.98	1	$2.98
0418072	2.75	1	$2.75
0418074	2.19	15	$32.85
0418075	2.52	5	$12.60"
	
	set existing_paragraphs to paragraphs of read_data
	
	set entry_values to {}
	
	repeat with paragraph_n in paragraphs of read_data
		set entry_value to word 1 of paragraph_n as number
		set entry_values to ((entry_values) & entry_value) as list
	end repeat
	
	set inventory_list to my insert_list_item(entry_values, new_entry_value)
	
	set inventory_output to ""
	
	repeat with this_entry in inventory_list
		set inventory_output to inventory_output & this_entry & return
	end repeat
	
	set amended_inventory to (desktop as text) & "Amended Inventory.txt"
	
	try
		open for access file amended_inventory with write permission
		set eof of file amended_inventory to 0
		write inventory_output to file amended_inventory starting at eof
		close access file amended_inventory
	on error
		close access file amended_inventory
	end try
	
	open file amended_inventory
	
end tell

-----

on insert_list_item(entry_values, new_entry_value)
	set existing_paragraphs to paragraphs of read_data
	if new_entry_value is in entry_values then
		return existing_paragraphs -- doesn't insert, if the value is already in the list
	else if new_entry_value < item 1 of entry_values then
		return new_entry & existing_paragraphs
	else
		repeat with i from 2 to count of entry_values
			if new_entry_value < item i of entry_values then return (items 1 thru (i - 1) of existing_paragraphs) & new_entry & (items i thru -1 of existing_paragraphs)
		end repeat
		
		if new_entry_value > last item of entry_values then
			return existing_paragraphs & new_entry
		else
			return (items 1 thru -2 of existing_paragraphs) & new_entry & last item of existing_paragraphs
		end if
	end if
end insert_list_item

-----


Five minutes later…

I spoke too soon, but I think I can iron out the kinks.

I’ll post a final script when I get it right.

Peter B.


The only (apparent) remaining problem with my last posted script was when a new entry had a numeric value less than an existing inventory entry.

This version fixes that. There may yet be other bugs, but I’ll quit ‘bugging’ the BBS for now…

Thanks yet once more.

Peter B.




global read_data
global new_entry

tell application "Finder"
	
	set new_entry to "0418043	2.75	2	$5.50"
	--set new_entry to "0418073	.45	8	$3.60"
	--set new_entry to "0418078	3.50	4	$14.00"
	
	set new_entry_value to word 1 of new_entry as number
	
	set read_data to "0418044	2.49	1	$2.49
0418045	2.47	2	$4.94
0418055	2.25	15	$33.75
0418058	3.21	1	$3.21
0418063	2.61	1	$2.61
0418065	4.28	1	$4.28
0418066	2.10	15	$31.50
0418068	5.40	1	$5.40
0418069	2.98	1	$2.98
0418072	2.75	1	$2.75
0418074	2.19	15	$32.85
0418075	2.52	5	$12.60"
	
	set existing_paragraphs to paragraphs of read_data
	
	set entry_values to {}
	
	repeat with paragraph_n in paragraphs of read_data
		set entry_value to word 1 of paragraph_n as number
		set entry_values to ((entry_values) & entry_value) as list
	end repeat
	
	set inventory_list to my insert_list_item(entry_values, new_entry_value)
	
	set inventory_output to ""
	
	repeat with this_entry in inventory_list
		set inventory_output to inventory_output & this_entry & return
	end repeat
	
	set amended_inventory to (desktop as text) & "Amended Inventory.txt"
	
	try
		open for access file amended_inventory with write permission
		set eof of file amended_inventory to 0
		write inventory_output to file amended_inventory starting at eof
		close access file amended_inventory
	on error
		close access file amended_inventory
	end try
	
	open file amended_inventory
	
end tell

-----

on insert_list_item(entry_values, new_entry_value)
	set existing_paragraphs to paragraphs of read_data
	if new_entry_value is in entry_values then
		return existing_paragraphs -- doesn't insert, if the value is already in the list
	else if new_entry_value < item 1 of entry_values then
		return (new_entry as list) & existing_paragraphs
	else
		repeat with i from 2 to count of entry_values
			if new_entry_value < item i of entry_values then return (items 1 thru (i - 1) of existing_paragraphs) & new_entry & (items i thru -1 of existing_paragraphs)
		end repeat
		
		if new_entry_value > last item of entry_values then
			return existing_paragraphs & new_entry
		else
			return (items 1 thru -2 of existing_paragraphs) & new_entry & last item of existing_paragraphs
		end if
	end if
end insert_list_item

-----