[comp.emacs] transpose,rotate,mirror,reverse text...

nieh@moose.steinmetz (nico nieh) (12/08/87)

The following problems occurred to me yesterday while I was editing
a file which contains matrices.

1. Is there an easy way to transpose a matrix in GNU-Emacs ?

      1 2 3 4 5                 1 6 2 1 9
      6 7 8 9 2                 2 7 4 3 8
      2 4 6 8 0        ====>    3 8 6 5 7
      1 3 5 7 9                 4 9 8 7 6
      9 8 7 6 5                 5 2 0 9 5

2. Is there an easy way to rotate a rectangular of text +90/-90 degrees ?

      1 2 3 4 5                 9 1 2 6 1
      6 7 8 9 2                 8 3 4 7 2
      2 4 6 8 0       =====>    7 5 6 8 3
      1 3 5 7 9                 6 7 8 9 4
      9 8 7 6 5                 5 9 0 2 5

3. Is there an easy way to mirror a rectangular of text (vertical/horizontal) ?
4. How about reverse a line or reverse a region ?

Above questions should be applied to both character and word boundary.

Can anyone out there give me some advices ?
     Ko-Haw Nieh
     General Electric Company 
     Corporate Research and Development
     nieh@ge-crd.arpa
     518-387-7431

evan@cunixc.columbia.edu (Evan Bigall) (12/10/87)

     | The following problems occurred to me yesterday while I was editing
     | a file which contains matrices.
     | 
     | 1. Is there an easy way to transpose a matrix in GNU-Emacs ?
     | 
     |       1 2 3 4 5                 1 6 2 1 9
     |       6 7 8 9 2                 2 7 4 3 8
     |       2 4 6 8 0        ====>    3 8 6 5 7
     |       1 3 5 7 9                 4 9 8 7 6
     |       9 8 7 6 5                 5 2 0 9 5


I know this is not exactly what you wanted, but if you just want to get it done
what I would do is:

  run apl in a subshell under emacs
  cut the text from the file into the shell and assign it to an apl variable.  
  use the apl transpose primitive function to transpose it 
	(or rotate it, or whatever you want, apl can do it all) 
  cut the result back into the file

This is how I would do it, but then I like apl.  Send me mail if you want
the details of how to do the apl stuff.

evan
-- 
      evan@cunixc.columbia.edu  or  EJB@yktvmh.bitnet  (914)789-7027
APL is a mistake, carried through to perfection.  It is the language of the
future for the programming techniques of the past.    -	Edsger Dijkstra

karl@haddock.ISC.COM (Karl Heuer) (12/11/87)

In article <8129@steinmetz.steinmetz.UUCP> nieh@moose.steinmetz (nico nieh) writes:
>The following problems occurred to me yesterday while I was editing
>a file which contains matrices.
>
>1. Is there an easy way to transpose a matrix in GNU-Emacs ?
>2. Is there an easy way to rotate a rectangular of text +90/-90 degrees ?
>3. Is there an easy way to mirror a rectangular of text (vertical/horizontal) ?
>4. How about reverse a line or reverse a region ?
>
>Above questions should be applied to both character and word boundary.

I have a program called "flip" that transposes an input stream by character.
I find this very useful for doing column-oriented operations in an editor
where line-oriented operations are the norm.  The program also has an option
to use fixed-size rectangles of characters as the quantum (someday I should
add an option for tab-separated quanta).  Request by e-mail if you want the
source code.

It probably wouldn't be too difficult to do with an awk script, either.

Karl W. Z. Heuer (ima!haddock!karl or karl@haddock.isc.com), The Walking Lint

weltyc@nysernic (Christopher A. Welty) (12/11/87)

In article <8129@steinmetz.steinmetz.UUCP> nieh@moose.steinmetz (nico nieh) writes:
>
>The following problems occurred to me yesterday while I was editing
>a file which contains matrices.
>
>1. Is there an easy way to transpose a matrix in GNU-Emacs ?
>
>      1 2 3 4 5                 1 6 2 1 9
>      6 7 8 9 2                 2 7 4 3 8
>      2 4 6 8 0        ====>    3 8 6 5 7
>      1 3 5 7 9                 4 9 8 7 6
>      9 8 7 6 5                 5 2 0 9 5
>

	Since emacs supports its own LISP, you can certainly write
such fuinctions quite easily.  In fact, I wrote this opne up quickly
as an example.  IT IS BY NMO MEANS EFFICIENT, there are a lot better
ways to do it, I just wrote it real quick.  If you position point at the beginning of a matrix which consists of elements separated by whitespace, and the last line of the matrix is followed by an empty line, this will put the transposed matrix after the original one.  ie start with

1 2 3
3 2 1
1 2 3

and end up with

1 2 3
3 2 1
1 2 3

1 3 1
2 2 2
3 1 3

Here it is:
 
(defun transpose ()
  ; from point to the first blank line is current matrix
  (interactive)
  (let ((bol) (matrix nil) (i 0) (len) (tmatrix nil))
    (while (not (eolp))
      (setq bol (point))
      (end-of-line)
      (setq matrix
	    (append matrix
		    (list (car
			   (read-from-string
			    (concat "("
				    (buffer-substring bol (point))
				    ")" ))))))
      (forward-line 1))
    ;  Now matrix is a list of lists, each sublist is a row
    (setq len (length (car matrix)))
    (while (< i len)
      (setq tmatrix
	    (append tmatrix
		    (list (mapcar '(lambda (x) (nth i x)) matrix))))
      (setq i (1+ i)))
    ; tmatrix is now the transformed matrix, with each sublist a row
    ; Now we print it out after the current matrix
    (mapcar '(lambda (x)
	       (newline 1)
	       (mapcar '(lambda (x)
			  (insert (format "%s " x)))
		       x))
	    tmatrix)))


Christopher Welty  ---  Asst. Director, RPI CS Labs
weltyc@cs.rpi.edu       ...!rutgers!nysernic!weltyc

rupley@arizona.edu (John Rupley) (12/12/87)

In article <1932@haddock.ISC.COM> karl@haddock.ima.isc.com (Karl Heuer) writes:
>In article <8129@steinmetz.steinmetz.UUCP> nieh@moose.steinmetz (nico nieh) writes:
>>The following problems occurred to me yesterday while I was editing
>>a file which contains matrices.
>>
>>1. Is there an easy way to transpose a matrix in GNU-Emacs ?
>>2. Is there an easy way to rotate a rectangular of text +90/-90 degrees ?
>>3. Is there an easy way to mirror a rectangular of text (vertical/horizontal) ?
>>4. How about reverse a line or reverse a region ?
>>
>>Above questions should be applied to both character and word boundary.
>
>I have a program called "flip" that transposes an input stream by character.
		<stuff deleted>
>It probably wouldn't be too difficult to do with an awk script, either.
						     ^^^^^^^^^^

True, awk makes it easy to do all that the original poster wanted. The 
example below is for text, ie for (2), (3), and (4); (1), for numbers, 
is even easier.

Following is a quickie awk script to load an array, which you can 
read out however you want.  I run new awk, but I think all is 
compatible with the old awk. 

The script is for text lines of variable length.  Manipulating 
numerical arrays is simpler (that's how I prototyped, if one can 
speak of prototyping an awk script).  Change in the gsub /re/
allows change from character to word boundary or to number, and
this can be done dynamically, at least in the new awk, and
through command line settings.  Things could be prettied up and
function calls would simplify, but its late and I'm doing this
for fun.

Some test output is given at the end of the script.

*******NB: about 140 lines follow, so hit return if you're bored....

John Rupley
 uucp: ..{ihnp4 | hao!noao}!arizona!rupley!local
 internet: rupley!local@megaron.arizona.edu
 telex: 9103508679(JARJAR)
 (H) 30 Calle Belleza, Tucson AZ 85716 - (602) 325-4533
 (O) Dept. Biochemistry, Univ. Arizona, Tucson AZ 85721 - (602) 621-3929

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

awk '
BEGIN	{
		FS=":"
	}

	{
		#put in dummy separator, here a :
		gsub(/./, "&:")
		#split line into fields in array scr
		split($0, scr, ":")
		i = i + 1
		j = 1 + 0
		imax = i + 0
		jmax[i] = NF - 1
		if (jmax[i] > jmaxmax)
			jmaxmax = jmax[i]
		#fill doubly dimensioned array from elements of scr
		#i index = input row
		#j index = input field (no more than 10000)
		#the dummy index k is to make readout easier
		for (j = 1 + 0; j <= jmax[i]; j = j + 1)
		{
			k = i*10000 + j
			array[k] = scr[j]
		}
	}

#now that the input is stuffed into an array,
#read it out any-which-way
END	{	
		#add spaces to obtain rectangular matrix
		#you can get rid of trailing spaces later, if you want
		for (i = 1 + 0; i <= imax; i = i + 1)
		{
			for (j = 1 + jmax[i]; j <= jmaxmax; j = j + 1)
			{
				k = i*10000 + j
				array[k] = " "
			}
		}
		#output whatever (function calls would be nicer)
		print ""
		print "send out what came in"
		for (i = 1 + 0; i <= imax; i = i + 1)
		{
			outstr=""
			for (j = 1 + 0; j <= jmaxmax; j = j + 1)
			{
				k = i*10000 + j
				outstr = outstr  array[k]
			}
			print outstr
		}
		print ""
		print "reverse left-right"
		for (i = 1 + 0; i <= imax; i = i + 1)
		{
			outstr=""
			for (j = jmaxmax; j > 0; j = j - 1)
			{
				k = i*10000 + j
				outstr = outstr  array[k]
			}
			print outstr
		}
		print ""
		print "reverse top-bottom"
		for (i = imax + 0; i > 0; i = i - 1)
		{
			outstr=""
			for (j = 1 + 0; j <= jmaxmax; j = j + 1)
			{
				k = i*10000 + j
				outstr = outstr  array[k]
			}
			print outstr
		}
		print ""
		print "rotate + 90 degrees"
		for (j = 1 + 0; j <= jmaxmax; j = j + 1)
		{
			outstr=""
			for (i = imax + 0; i > 0; i = i - 1)
			{
				k = i*10000 + j
				outstr = outstr  array[k]
			}
			print outstr
		}
	}'
		
++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++

output for the following test block:

abcdefg
hijkl
mnopqrstu
v wx  yz
          0

is............

send out what came in
abcdefg    
hijkl      
mnopqrstu  
v wx  yz   
          0

reverse left-right (mirror vertically) (reverse region)
    gfedcba
      lkjih
  utsrqponm
   zy  xw v
0          

reverse top-bottom (mirror horizonatally)
          0
v wx  yz   
mnopqrstu  
hijkl      
abcdefg    

rotate + 90 degrees
 vmha
  nib
 wojc
 xpkd
  qle
  r f
 ys g
 zt  
  u  
     
0    

......and whatever else one's heart desires

+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++