Take the 2-minute tour ×
Unix & Linux Stack Exchange is a question and answer site for users of Linux, FreeBSD and other Un*x-like operating systems.. It's 100% free, no registration required.

I have the following line in a file :

[[0, [0, '1']], [1, [0, '2']], [2, [0, '3']], [3, [0, '4']]]
[[0, [1, '5']], [1, [1, '6']], [2, [1, '7']], [3, [1, '8']]]
[[0, [2, '9']], [1, [2, '10']], [2, [2, '11']], [3, [2, '12']]]

Is there a way to sort them on the first character (0,1,2 or 3) in the inner list element so that I will end up with the following:

[[0, [0, '1']], [0, [1, '5']],[0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']],[1, [2, '10']]] 

and so on?

share|improve this question
6  
Sounds like you should be using a programming language that can parse that structure. –  Ignacio Vazquez-Abrams Dec 3 '13 at 16:12
2  
You don't want to sort them, you want to change their structure. You are creating new arrays that contain the elements of the old ones but completely changing the original arrays, that is not sorting. Since this is not a human readable format, I assume it is part of a larger project, are you using any particular programming language for this? –  terdon Dec 3 '13 at 16:38
add comment

1 Answer

up vote 2 down vote accepted

Well, this is not particularly elegant but it will do what you need. At least, it does on the example you posted:

perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
sed 's/,\]$/\]/' | sort

Running the command above on a file called file.txt that contains the lines from your example gives the following output:

[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]

Explanation

I will not explain in detail since this is actually a small program and uses quite a few features of Perl. The basic idea of the Perl script is to find all cases of [\d, [.+?]] where \d is any number and .+?]] is everything up to the first ]]. This will basically collect all the different sub-arrays or tuples or whatever these are and save them in a hash of arrays whose key is the first digit, the one you want to sort on. Once the whole file has been processed, it will print each array of the hash. This is the output of the script alone:

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt 
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']],]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']],]
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']],]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']],]

I am separating each sub array with a , but that means I get an extra one at the end so I use sed to remove that.

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
>           END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
> sed 's/,\]$/\]/' 
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]

Finally, you also wanted this sorted but since they now are organized by their first character, a simple sort will do:

$ perl -ne 'while(s/(\[(\d),\s*\[.+?\]\])//){push @{$k{$2}},$1 . ",";} 
          END{ print "[@{$k{$_}}]\n" for keys(%k)}' file.txt | 
sed 's/,\]$/\]/' | sort
[[0, [0, '1']], [0, [1, '5']], [0, [2, '9']]]
[[1, [0, '2']], [1, [1, '6']], [1, [2, '10']]]
[[2, [0, '3']], [2, [1, '7']], [2, [2, '11']]]
[[3, [0, '4']], [3, [1, '8']], [3, [2, '12']]]
share|improve this answer
    
My eyes hurt 8-) –  slm Dec 3 '13 at 17:12
1  
@slm try taking your glasses off, it looks better when not in focus :) –  terdon Dec 3 '13 at 17:27
add comment

Your Answer

 
discard

By posting your answer, you agree to the privacy policy and terms of service.

Not the answer you're looking for? Browse other questions tagged or ask your own question.