Swap rows and columns of a list

LiveCode is the premier environment for creating multi-platform solutions for all major operating systems - Windows, Mac OS X, Linux, the Web, Server environments and Mobile platforms. Brand new to LiveCode? Welcome!

Moderators: FourthWorld, heatherlaine, Klaus, kevinmiller, robinmiller

Post Reply
paulclaude
Posts: 121
Joined: Thu Mar 27, 2008 10:19 am

Swap rows and columns of a list

Post by paulclaude » Tue Jan 12, 2016 1:46 pm

There's an easy and fast way to swap rows and columns of a list (better than a classic "repeat" loop)?

For instance I have a list like this:

1,2,3
4,5,6
7,8,9

and I need it to convert into a list like this:

1,4,7
2,5,8
3,6,9

MaxV
Posts: 1580
Joined: Tue May 28, 2013 2:20 pm
Contact:

Re: Swap rows and columns of a list

Post by MaxV » Tue Jan 12, 2016 2:00 pm

The following code works with any dimension list, field 1 is input and field 2 is output:

########CODE#######
on mouseUp
put field 1 into temp
set columndel to comma
split temp by column
repeat for each element tElem in temp
repeat for each line tLine in tElem
put tLine & comma after field 2
end repeat
delete last char of field 2
put return after field 2
end repeat
end mouseUp
#####END OF CODE#####
Livecode Wiki: http://livecode.wikia.com
My blog: https://livecode-blogger.blogspot.com
To post code use this: http://tinyurl.com/ogp6d5w

paulclaude
Posts: 121
Joined: Thu Mar 27, 2008 10:19 am

Re: Swap rows and columns of a list

Post by paulclaude » Tue Jan 12, 2016 2:13 pm

Thank you MaxV, I had already wrote this code. There's difference in speed with large list between our two codes?

Code: Select all

function swap listt, theItDel
    if theItDel <> empty then set the itemDel to theItDel -- sets the desired delim
   repeat with a=1 to the number of lines in listt
      put line a of listt into theLine
      repeat with x=1 to the number of items in theLine
         put item x of theLine into item a of line x of theNewData
      end repeat
   end repeat
   return theNewData
end swap

Klaus
Posts: 14199
Joined: Sat Apr 08, 2006 8:41 am
Contact:

Re: Swap rows and columns of a list

Post by Klaus » Tue Jan 12, 2016 2:45 pm

Hi Paul,
paulclaude wrote:There's difference in speed with large list between our two codes?
yes, "repeat for each..." is always a lot faster that "repeat with..."!


Best

Klsud

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Swap rows and columns of a list

Post by sritcp » Tue Jan 12, 2016 4:41 pm

Hi paulclaude:

MaxV's code is different from yours in that it uses it converts the list into an array.
If you can have your data in an array form, many operations are quick and efficient.
Here's a variant of MaxV's code:

Code: Select all

on mouseUp
   local temp
   put field "Input" into temp
   set the columnDel to comma
   split temp by column
   combine temp by comma
   replace return with tab in temp
   replace comma with return in temp
   replace tab with comma in temp
   put temp into field "Output"
end mouseUp
Regards,
Sri

paulclaude
Posts: 121
Joined: Thu Mar 27, 2008 10:19 am

Re: Swap rows and columns of a list

Post by paulclaude » Wed Jan 13, 2016 10:23 am

Thanks, it's faster than my code

MaxV
Posts: 1580
Joined: Tue May 28, 2013 2:20 pm
Contact:

Re: Swap rows and columns of a list

Post by MaxV » Fri Jan 15, 2016 11:28 am

sritcp wrote:Hi paulclaude:

MaxV's code is different from yours in that it uses it converts the list into an array.
If you can have your data in an array form, many operations are quick and efficient.
Here's a variant of MaxV's code:

Code: Select all

on mouseUp
   local temp
   put field "Input" into temp
   set the columnDel to comma
   split temp by column
   combine temp by comma
   replace return with tab in temp
   replace comma with return in temp
   replace tab with comma in temp
   put temp into field "Output"
end mouseUp
Regards,
Sri
Your code doesn't work on a 12x12, this:

Code: Select all

1,2,3,4,5,6,7,8,9,10,11,12
13,14,15,16,17,18,19,20,21,22,23,24
25,26,27,28,29,30,31,32,33,34,35,36
37,38,39,40,41,42,43,44,45,46,47,48
49,50,51,52,53,54,55,56,57,58,59,60
61,62,63,64,65,66,67,68,69,70,71,72
73,74,75,76,77,78,79,80,81,82,83,84
85,86,87,88,89,90,91,92,93,94,95,96
97,98,99,100,101,102,103,104,105,106,107,108
109,110,111,112,113,114,115,116,117,118,119,120
121,122,123,124,125,126,127,128,129,130,131,132
133,134,135,136,137,138,139,140,141,142,143,144  
change into this, that is wrong:

Code: Select all

1,13,25,37,49,61,73,85,97,109,121,133
10,22,34,46,58,70,82,94,106,118,130,142
11,23,35,47,59,71,83,95,107,119,131,143
12,24,36,48,60,72,84,96,108,120,132,144
2,14,26,38,50,62,74,86,98,110,122,134
3,15,27,39,51,63,75,87,99,111,123,135
4,16,28,40,52,64,76,88,100,112,124,136
5,17,29,41,53,65,77,89,101,113,125,137
6,18,30,42,54,66,78,90,102,114,126,138
7,19,31,43,55,67,79,91,103,115,127,139
8,20,32,44,56,68,80,92,104,116,128,140
9,21,33,45,57,69,81,93,105,117,129,141
Livecode Wiki: http://livecode.wikia.com
My blog: https://livecode-blogger.blogspot.com
To post code use this: http://tinyurl.com/ogp6d5w

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Swap rows and columns of a list

Post by sritcp » Fri Jan 15, 2016 3:54 pm

MaxV:

You are correct.
Arrays seem to retain the order of the columns while they are arrays, but lose the order when combined into a list.

Thanks for the insight,
Sri

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Swap rows and columns of a list

Post by sritcp » Fri Jan 15, 2016 8:27 pm

sritcp wrote:........
Arrays seem to retain the order of the columns while they are arrays, but lose the order when combined into a list. .....
One way to get around this problem is to save the keys and sort by them.
Here's above code modified to that:

Code: Select all

on mouseUp
   local temp, tCounter
   put field "Input" into temp
   set the columnDel to comma
   split temp by column
   combine temp by comma and ":"
   replace return with tab in temp
   replace comma with return in temp
   replace tab with comma in temp
   set the itemDel to ":"
   sort lines of temp ascending numeric by item 1 of each
   put 1 into tCounter
   repeat for each line tLine in temp
      delete item 1 of line tCounter of temp
      add 1 to tCounter
   end repeat
   put temp into field "Output"
end mouseUp
This should produce correct results.

Regards,
Sri

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Swap rows and columns of a list

Post by bn » Sat Jan 16, 2016 1:25 am

Hi Sri,

your solution gives correct result with the test Matrix 12:12 from above.

However in your code using the repeat for each form you modify the container you are referencing, in this case temp

Code: Select all

repeat for each line tLine in temp
  delete item 1 of line tCounter of temp
  add 1 to tCounter
end repeat
the dictionary warns against this technique
Important: In any of the for each loops, you should not change the labelVariable or container in a statement inside the loop. Doing so will not cause a script error, but will almost certainly produce unexpected results.
This is why I comment on this because new users of Livecode might think this is a viable technique, it is NOT

In a repeat with i = 1 to x form you can change the container, that is one of the reasons why it is a lot slower than repeat for each, but not in the repeat for each form: leave the container alone.

Kind regards
Bernd

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Swap rows and columns of a list

Post by sritcp » Sat Jan 16, 2016 2:02 pm

bn wrote:

Code: Select all

repeat for each line tLine in temp
  delete item 1 of line tCounter of temp
  add 1 to tCounter
end repeat
the dictionary warns against this technique .........
Hi Bernd:

Thanks for pointing this out. Yes, changing the container that is being looped over is dangerous.
I should have made a copy of temp and changed the copy.

Code: Select all

put temp into temp2
put 1 into tCounter
repeat for each line tLine in temp
  delete item 1 of line tCounter of temp2
  add 1 to tCounter
end repeat
This would still let us use "repeat for ....", won't it?
(Of course, in this example there is no advantage to using this over "repeat with i = ..." because we are changing all lines, but if only a few lines are changed conditionally, this would preserve the speed advantage of "repeat for ....". Am I right?)

Thanks,
Sri

bn
VIP Livecode Opensource Backer
VIP Livecode Opensource Backer
Posts: 4172
Joined: Sun Jan 07, 2007 9:12 pm

Re: Swap rows and columns of a list

Post by bn » Sat Jan 16, 2016 2:51 pm

Hi Sri,
This would still let us use "repeat for ....", won't it?
(Of course, in this example there is no advantage to using this over "repeat with i = ..." because we are changing all lines, but if only a few lines are changed conditionally, this would preserve the speed advantage of "repeat for ....". Am I right?)
To do the changes on a copy of the container that is looped on should not cause any trouble. As you point out it forces Livecode to count to the desired line every time.

I tested

Code: Select all

 repeat with i = 1 to the number of lines of temp
         delete item 1 of line i of temp
      end repeat
and it is virtually equally fast.

What I do at times, which is also off-label, is to change the labelVariable since I consider the labelVariable an ordinary variable which is filled anew with each iteration. Changing the labelVariable and storing the modified labelVariable in a different container works for me reliably, although IT IS NOT WHAT THE DICTIONARY RECOMMENDS.

But I never change the container in a "for each" loop because I think the speed advantage comes from the fact that Livecode can map the delimiter (line or item etc) once before starting the "for each" loop and then relies on that map, i.e. LC does not recount the delimiters nor their location with each loop.

Kind regards

Bernd

sritcp
Posts: 431
Joined: Tue Jun 05, 2012 5:38 pm

Re: Swap rows and columns of a list

Post by sritcp » Sun Jan 17, 2016 12:47 am

bn wrote:..... As you point out it forces Livecode to count to the desired line every time......
bn wrote:I tested

Code: Select all

repeat with i = 1 to the number of lines of temp
         delete item 1 of line i of temp
      end repeat
and it is virtually equally fast.
Only in this specific example. If instead, we had 1000 rows, for example, and only 20 needed to be updated as a result of running the repeat loop, you should find that it is significantly faster than "repeat with i=1..." option. So, the point is still valid.

In fact, I have been trying to get away from having to use "repeat with i=1... " as much as possible as it draws a penalty even in the relatively small (2000-2500 records) datasets I work with. Sometimes, the operations are such that "repeat for ..." just won't do. I think I have stumbled upon this trick of using a copy of the container to get around.

I am also pretty sure the same tactic would work with the labelVariable -- making a copy of the lableVariable and modifying that.

Regards,
Sri

Post Reply