reordering without sorting

Discuss Programming
worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

reordering without sorting

Post by worker201 » Mon Dec 12, 2005 8:55 pm

I have a text file, which consists of numerical pairs, like so:

Code: Select all

-89.977365	30.258552
-89.977512	30.258625
-89.978026	30.258699
-89.978392	30.258992
-89.979052	30.259065
The columns are separated by tabs, and each ends with a newline.

What I want to do is reorder them in reverse. For example, the 5 pairs above would end up as:

Code: Select all

-89.979052	30.259065
-89.978392	30.258992
-89.978026	30.258699
-89.977512	30.258625
-89.977365	30.258552
I absolutely do not want them in numerical order (even though this particular example happens to be in numerical order). These are longitudes and latitudes describing the coast of Louisiana, and the order in which each point is drawn is important. The coast is broken up into a bunch of segments, and the drawing has to be continuous from segment to segment. So, if one segment is moving in one direction, and another is moving the opposite way, there will be a huge linear jump as it goes from the last point of segment a to the last point of segment b.

Does that make any sense?

All I want is a quick and dirty routine that will flip a simple 2-column table upside down. I tried piping from awk to sort, but sort tries to compare the numbers, which is no good. I can't find an awk method for this. And I can't find a Perl method either, although I might not notice a good Perl script if I saw one.

I suppose I could read each item into an array, and then print them into the new file backwards from the array. But I would think that someone has made this a lot easier in some language - all I need to do is figure out which one.

Any help is appreciated. Sed, awk, perl, bash, C, whatever.

ZiaTioN
administrator
administrator
Posts: 460
Joined: Tue Apr 08, 2003 3:28 pm
Contact:

Post by ZiaTioN » Mon Dec 12, 2005 9:07 pm

Very easy in perl. reverse() is what you would be looking for.

Code: Select all

#!/usr/bin/perl -w

use strict;
my @rev;
push (@rev, $_) while (<DATA>);
print reverse(@rev);

__DATA__
-89.977365   30.258552
-89.977512   30.258625
-89.978026   30.258699
-89.978392   30.258992
-89.979052   30.259065
The reverse() function needs to be given an array or an array reference. In this example I constructed the array by looping through DATA and pushing each object onto the array stack. You can create the array any way you want but the important part is to give reverse() an array or array reference.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Mon Dec 12, 2005 9:27 pm

Or:

Code: Select all

$ sort -r file.txt
For numeric sort add "-n", for dictionary (alpha) sort add "-d". See "man sort".

worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

Post by worker201 » Mon Dec 12, 2005 9:31 pm

Void, your version using sort changes the numerical order of the records. I only want to reverse their physical order.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Mon Dec 12, 2005 9:33 pm

It gives me the same answer you say you want it to end up like. Maybe I don't understand (even though I do understand lat/lon as I have done a lot of work in this area years ago). Do you have another sample that wouldn't come out right and an example of how you would like it to come out?

worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

Post by worker201 » Mon Dec 12, 2005 9:41 pm

Code: Select all

-89.984259	30.263686
-89.984553	30.263906
-89.984553	30.263979
-89.983966	30.263906
-89.983746	30.263686
As you can see, these 5 points define a shallow curve, with the extreme eastern value being held by points 2 and 3.

sort -r

Code: Select all

-89.984553	30.263979
-89.984553	30.263906
-89.984259	30.263686
-89.983966	30.263906
-89.983746	30.263686
sort -r has sorted the list in numerical order, and the extreme east is now points 1 and 2. sort -r again yields pts 4 and 5.

Goal:

Code: Select all

-89.983746	30.263686
-89.983966	30.263906
-89.984553	30.263979
-89.984553	30.263906
-89.984259	30.263686
In the idealized version, the eastern extremes would be at points 3 and 4, the exact opposite of the original. The first has become the last, the last has become the first, the 2nd is now 4th, and the 3rd remains the same.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Mon Dec 12, 2005 9:58 pm

Yeah, the Perl method is an easy one like ZiaTioN suggested. If you want to be able to just cat a file to it you can put this in a script:

Code: Select all

#!/usr/bin/perl
my @arr = <STDIN>;
print reverse(@arr);
Then:

Code: Select all

$ ./perlsort.pl < forwardfile.txt > reversefile.txt

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Mon Dec 12, 2005 10:12 pm

Better yet:

Code: Select all

$ tac file.txt
I KNEW there was a command for it but I couldn't think of it. :) Here are 7 other ways to reverse a file:

http://www.samag.com/documents/s=9766/s ... /0506g.htm

worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

Post by worker201 » Tue Dec 13, 2005 3:02 pm

tac

cat backwards

:roll:
I knew there had to be a simple way to do this. Thank goodness you found it. I was about to use method #2, which involves awk and some arrays, which is just too much work for something I just want to run off real quick.

ZiaTioN
administrator
administrator
Posts: 460
Joined: Tue Apr 08, 2003 3:28 pm
Contact:

Post by ZiaTioN » Wed Dec 14, 2005 4:08 am

The only problem with tac is it is limited to getting the data from a text file. In your case, that may not be a hinderance because that is what you are doing but it is still an overall limitation. It just depends on what you are doing.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Wed Dec 14, 2005 9:02 am

ZiaTioN wrote:The only problem with tac is it is limited to getting the data from a text file. In your case, that may not be a hinderance because that is what you are doing but it is still an overall limitation. It just depends on what you are doing.
As opposed to what other kind of file? It can be piped to as well if you are implying that you have to pass it a filename to read directly which is not the case.

worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

Post by worker201 » Wed Dec 14, 2005 2:44 pm

That's why there's 8 different ways to do it - in case one is inconvenient for your purposes. If this operation was part of a larger perl or awk script, one of the other methods might have been more appropriate.

As for me,

Code: Select all

tac segmenta > segmenta1
worked just fine.

ZiaTioN
administrator
administrator
Posts: 460
Joined: Tue Apr 08, 2003 3:28 pm
Contact:

Post by ZiaTioN » Wed Dec 14, 2005 3:56 pm

Void Main wrote:
ZiaTioN wrote:The only problem with tac is it is limited to getting the data from a text file. In your case, that may not be a hinderance because that is what you are doing but it is still an overall limitation. It just depends on what you are doing.
As opposed to what other kind of file? It can be piped to as well if you are implying that you have to pass it a filename to read directly which is not the case.
No other kind of file, that is the point. Reading data from a file is not the only way to get a list of data. What if you were reading from a database? How about reading from a socket? Maybe even reading from a file but only extracting the data into an array if it meets specific requirement and then reversing it and printing out to another file. I can go on if you like?

worker201
guru
guru
Posts: 668
Joined: Sun Jun 13, 2004 6:38 pm
Location: Hawaii

Post by worker201 » Wed Dec 14, 2005 5:14 pm

In case anyone was interested in seeing exactly what I am doing, here's an image of the Louisiana coastline. Although it isn't filled right now, the coast is now represented by a series of polygons that I can easily fill with anything I choose.

In the image, New Orleans is represented with a red dot, and the Mississippi River is colored in blue.

Image

It's amazing what one can do with tac, cat, gedit, awk, and ggv!
Last edited by worker201 on Wed Dec 14, 2005 5:15 pm, edited 1 time in total.

User avatar
Void Main
Site Admin
Site Admin
Posts: 5716
Joined: Wed Jan 08, 2003 5:24 am
Location: Tuxville, USA
Contact:

Post by Void Main » Wed Dec 14, 2005 5:15 pm

It was fairly obvious it wasn't coming from a database or there would have had to be some order on the data anyway (order by). It was obvious to me that it was in a flat file in a certain order that needed to be reversed. Otherwise you are correct, but I still can use tac even with a database:

Code: Select all

echo "select lat,lon from island" | mysql | tac
:) Of course with no "order by" statement the data is going to come out in no predictable order and using an order by statement would sort the data which is not want he wanted to do. So for the database to be relevent there would have to be another column I would think, to show parent or child row.

Post Reply