Link to home
Start Free TrialLog in
Avatar of jameskane
jameskane

asked on

reordering a list

I have two lists dynamically generated from a form. EG

List one (text1,text2,text3,text4)
List two (2,4,1,3)

The first list is created by the user selecting items on a form using the checkbox. On selecting the item, he/she then enters an order number into a field adjoining the checkbox.

The form is submitted and I have two lists, as above. Text1 has a list order of 2, text 2 has a list order of 4, text3 has a list order of 1 and text4 has a list order of 3.

The objective is to create a new version of list one, where the order of the elements is 1,2,3, 4 - vrs their current order of 2,4,1, 3. The reordered list is then used to create a  table listing of list1 elements, ordered by 1,2,3,4.

Can someone give me a pointer as to how I might do this. First thought is to create a two dimensional array, sort it and then generate a new version of list1 ?

Many thanks for any help

james
Avatar of _agx_
_agx_
Flag of United States of America image

Assuming all of the entries are valid,  it's certainly possible. But this structure has the potential for a few pitfalls. For example, if a user skips an entry - or enters an invalid value like "12" (there aren't 12 elements).  What about using a different mechanism for the ordering, like a multi-select list with options to shift items up or down. Is that possible?

ASKER CERTIFIED SOLUTION
Avatar of _agx_
_agx_
Flag of United States of America image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
Avatar of jameskane
jameskane

ASKER

Thanks as always agx for the rapid response !

I am not too  worried about the fragility. The user will be presented with the ordered list - and if it does not look correct he can go back to the form and change the order numbers he entered.

I did come across the idea of being able to shift items up and down, but could not figure it out !! I certainly looked impressive. The scenario I had in mind was that the user would see the list (as per current thinking) after submitting the form, but with the up and down arrows to allow for manual sorting. The mechanism would be supported by the two lists uploaded to the action page from the form.

If you know of a pointer to a support for this I would appreciate it.

Will try your solution in a couple of hours, but it looks good to me !!

James
>> The reordered list is then used to create a  table listing of list1 elements, ordered by 1,2,3,4

this makes me think you are actually storing the data as comma-delimited list in your table...
is that right? if it is, i strongly advise you to re-think your approach before it is too late.

if you were to normalize your db and store each list item as a separate record in a linked table, then you would not need to worry about re-ordering the list: just store the item's position in item_ordinal column.

if you are storing the list as column value in your db, i can explain more on how to change it.

Azadi
That's right azadi - that table is a repository for the different selections (playlists) that the user creates from his inventory of cd tracks. If he wants a playlist from the repository, he brings up the repository table and, selects the playlist and then it is dynamically generated from the stored list.

Unfortunately this project is not a green field project - he has 2500 tracks stored on an access database which has no sense at all of what is needed for a database application. He uses some of the access functionality to create reports... which great difficulty. There were no key fields or anything like that.

Each track has a title, and he entered those with commas !!!!!  So I had to do a big cleanup to rid myself of the commas. Comma cleaning is something I build into the action page so I am not going to get into difficulty if he forgets not to enter commas. I find that the spaces dont matter.

Having said all of that, now  you have me worried !!
Oh, I thought you meant meant html table.. not db table.  I totally agree with Azadi. Normalize. Storing csv lists is just bad news.  Unfortunately, I have to head out now. But I'm sure Azadi will explain it :)
Thanks very much, that works. Could  you let me know how to change the order from descending to ascending - needs a desc tag somewhere ?

Thanks also to you both for your advise on the design. I am not too worried on reflection about putting the listing into the database. Its a bounded action in the context of the total application. The main processing does not require its use - which is along standard lines;

Thanks again.
Azadi,

there seems to be a problem with the sorting code. It refuses to work correctly for lists of more that 5 items. Its not at all clear to me why this should be the case.

SO,  the first example below works, but the second does not.

<cfset list1 = "textone,texttwo,textthree,textfour,xxx">
<cfset list2 = "2,4,1,3,5">

<cfset list1 = "textone,texttwo,textthree,textfour">
<cfset list2 = "2,4,1,3">

Maybe its something obvious to your eye, but its a mystery to me !

james
> how to change the order from descending to ascending

If you mean reverse the order of the final list:
http://cflib.org/index.cfm?event=page.udfbyid&udfid=51
Thanks very much, that is very interesting, but another thing.The problem is that azadi's code works fine for 4 item lists, but not for lists with more than 4. Just cant figure that out

James
Did azadi post code? I thought only I did.  It should have no problem with more than 4 items.  It works for me. Does the data itself contain commas? Maybe that's throwing it off.
sorry  agx, getting late... loosing it a bit.

If you replace the list 1 and List 2 in the example code with the one in my previous mail you will see the problem. Its not a case of commas, I am clean on that. I tried it with list items which had spaces and apostrophes and that worked, no problem. Its just that when it goes over 4 items, it gets lost. If you just replace your example lists with the ones I sent you will see it

again, apologies for the mix up

james
I must be misunderstanding :) because in both cases I see what I would expect:

newList = text2,text4,text1,text3,xxx
newList = texttwo,textfour,textone,textthree

What do you expect to see in the first and second case?
<cfset list1 = "textone,texttwo,textthree,textfour,xxx">
<cfset list2 = "2,4,1,3,5"

for the above I expect

xxx,texttwo,textfour,textone,textthree

the code does not seem to cope with the fifth item XXX, which I would have expected to be first, ahead of texttwo

James
> the code does not seem to cope with the fifth item XXX

No, I must be misunderstanding the logic you're trying to apply ;-)  I thought what you wanted was:

Create a new list, using:
<cfset list2 = "2,4,1,3,5">
- First, grab the item in position 2  (texttwo)   ie   texttwo
- Then add the item in position 4  (textfour)    ie   texttwo,textfour
- Then add the item in position 1  (textone)    ie   texttwo,textfour,textone
.. and so on...

No agx. What I have are items which have been selected and assigned an "order" number - Ie the order it should occupy in the total list of (in this example) 5.
textone has a ordering number of 2 and is locked to that number
texttwo has an ordering number of 4 and is locked to that number
etc

the routine should order the items as 5,4,3,2,1 and then decode that order by associating each number with its assigned item. So we get
XXX,texttwo,textfour,textone, textthree

================== ref===============

<cfset list1 = "textone,texttwo,textthree,textfour,xxx">
<cfset list2 = "2,4,1,3,5"
If:
      items =  textone,texttwo,textthree,textfour,xxx
      itemOrder = "2,4,1,3,5"

> the routine should order the items as 5,4,3,2,1

   Does this refer to "items" or "itemOrder"? If items, what is a literal representation of 5,4,3,2,1?  
This refers to items. These items are textone, texttwo etc. The numbers give for each item the position that item should take in any printout. TEXTONE should occur in second 2 position, Texttwo should occur in fourth 4th position..... etc.


In practical terms, The user selects items from a long form listing.
After selecting each item he then enters into a text field ( immediately beside the checkbox used to select the item) a number. That number defines the positioning the chosen item should take in a printout of the total set of chosen items



On submitting the form to the action page, we have two lists - one giving the names of the items chosen and the other giving the ordering positions for each of the items.

Now we want to get a printout  - a single column of rows with the names of the items. The printout is

xxx
 texttwo
 texxtfour
 textone
 textthree

or (and preferably ) the above is reverse order.

Thanks very much for persevering with this !

James
> the routine should order the items as 5,4,3,2,1
>>> If items, what is a literal representation of 5,4,3,2,1?

I think what may be confusing me is that you're giving the final results in reverse order, not the step before that :)  I think the original code works, but the "reverse order" part adds another step.  It's not as simple as just reversing the whole list.  So I'm trying to understand that extra step, so I can figure out the modifications needed.

So given items " textone,texttwo,textthree,textfour,xxx", what's a literal representation of that intermediary step ie "5,4,3,2,1"?
Yes, it is the extra "reverse" step that's the problem.  Given the values:

<cfset items = "items = textone,texttwo,textthree,textfour,xxx">
<cfset itemOrder = "2,4,1,3,5">

The attached code should give you:

items = textone,texttwo,textthree,textfour,xxx
itemOrder = 2,4,1,3,5
newList = xxx,texttwo,textfour,textone,textthree

<cfset items = "text1,text2,text3,text4,xxx">
<cfset itemOrder = "2,4,1,3,5">
<!--- remove any non-numeric values --->
<cfset itemOrder = reReplace(itemOrder, "[^0-9,]", "", "all")>

<cfif listLen(items) eq listLen(itemOrder)>
	<cfset newList = "">
	<cfloop from="#listLen(itemOrder)#" to="1" index="revPos" step="-1">
		<!--- NOTE: This will throw an error if #foundAt# is not a valid list position --->
		<cfset foundAt = listFind(itemOrder, revPos)>
		<cfset foundValue = listGetAt(items, foundAt)>
		<cfset newList = listAppend(newList, foundValue)>
	</cfloop>
	<cfoutput>
		items = #items#<br>
		itemOrder = #itemOrder#<br>
		newList = #newList#<br>
	</cfoutput>
<cfelse>
	ERROR: Unequal number of elements or invalid positions found
</cfif>

Open in new window

Agx, that works nicely. Sorry for not getting back sooner, but my internet service was interrupted for several days.

If you have a final second, could you let me know how this line might be modified to reverse the order - which currently is 5,4,3,2,1. It would be better if it were 1,2,3,4,5

<cfloop from="#listLen(itemOrder)#" to="1" index="revPos" step="-1">

Many thanks again for  your great help.

James
I didn't test this, but I think changing the loop from descending to ascending order should do it.  ie From 1 ...To 5 instead of From 5 ... To 1.  You should probably change the variable name too. Since "rev[erse]Pos[ition]" no longer applies ;-)

<cfloop from="1" to="#listLen(itemOrder)#" index="revPos">
GREAT, just tested it and it works fine.

Cant tell you how much I appreciate your help !!


James
As always, you're very welcome!