read multiple lines and consolidate to single line [closed] - perl

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 9 years ago.
Improve this question
I want to process a file in such a way that, read from multiple lines and make a new file which will have a single line corresponding to this.
For eg.:
Input File:
12345 1 - - -
12346 - 2 - 4
12347 - - 3 -
12348 5 - - -
12349 - 6 - 8
12350 - - 7 -
Output file :
12346 1 2 3 4
12349 5 6 7 8
Take 3 lines to make a complete row.
How to do this in perl?

Do it in 3 simple steps:
Create a hash, keeping 1st word as key.
Read from files and keep the input in an array.
Print the elements to a new file against each each key.

perl -lane'
$r = $. % 3;
$f = $F[0] if $r==2;
$arr[$_] += $F[$_] for 1 .. $#F;
if (!$r) { print "$f #arr"; #arr=() }
' file
output
12346 1 2 3 4
12349 5 6 7 8

i think this will help you,if any clarification let me know:
input file is:
12345|1|-|-|-
12346|-|2|-|4
12347|-|-|3|-
12348|5|-|-|-
12349|-|6|-|8
12350|-|-|7|-
script
use strict;
use warnings;
sub processor{
(my #tmp )=#_;
my #inner;
shift(#tmp);
foreach my $element(#tmp){
$_=$element;
if((m/[0-9]/)){
push(#inner,$element);
}
}
return #inner;
}
open(INFILE,"infile.dat") or die "$!";
open(OFILE,">outfile.dat") or die "$!";
my #ecollector;
my $keyVal;
my $counter;
while(<INFILE>){
chomp($_);
my #tmp=split('\|',$_);
if(($. % 3) ne 0){
if(($. % 3) eq 2){ $keyVal=$tmp[0];}
push(#ecollector,processor(#tmp));
}
else{
push(#ecollector,processor(#tmp));
print OFILE "$keyVal\t".join("\t",sort(#ecollector))."\n";
#ecollector=();
}
}
close(INFILE);
close(OFILE);

This is my solution. input, and output files are 1st and 2nd argument from command-line:
#!/usr/bin/perl
use warnings;
use strict;
open(DATA, "<", $ARGV[0]) or die $!;
open(OUTPUT, ">", $ARGV[1]) or die $!;
my $count = 0;
my $id = 0;
my #arr;
foreach (<DATA>){
chomp;
my #data;
# if line is not empty
if($_ ne ""){
#data = split(" ", $_);
$id = $data[0];
# merge data
for(my $i = 1; $i <= $#data; $i++){
if($data[$i] ne "-"){
$arr[$i] = $data[$i];
}
}
$count++;
if ($count == 2){
$arr[0] = $id;
} elsif ($count == 3){
# reset countable variable
$count = 0;
# print output
print OUTPUT join " ",#arr,"\n";
}
}
}
close(DATA);
close(OUTPUT);

Related

Prevent perl script from new line

I have a Perl script:
$i=0;
while ( ($num = <STDIN>) =~ /\S/ ) {
push #lines, $num; $i++;
print ("$num"x"$i")."\n";
}
It prints this:
3
3
4
4
4
5
5
5
5
But I want it to print this:
3
3
4
4 4
5
5 5 5
How can I prevent Perl from printing a new line after every print?
I have tried this method, as you can see in the code snippet:
$num x $i
You probably need chomp($num); which will remove your input newline at the end of $num.
my $i=0;
while ( (my $num = <STDIN>) =~ /\S/ ) {
chomp($num);
$i++;
print "$num " x $i, "\n"
}
Or you could just:
print "$& " x ++$i, "\n" while <STDIN>=~/\d+/;
(Also, when asking code questions you should strip down your example to only contain what is relevant. Your push #lines, $num can only contribute to confuse potential answerers)

Transposing an array of elements

I am trying to transpose an array.
I tried the following code...
#! /usr/bin/perl
use strict;
use warnings;
use autodie;
open my $fh, '<',"op.txt" || die "$!";
open my $wh , '>',"pwl.txt" || die "$!";
select ($wh);
while (my $line = <$fh>) {
my #rows = $line;
my #transposed;
for my $row (#rows) {
for my $column (0 .. $#{$row}) {
push(#{$transposed[$column]}, $row->[$column]);
}
}
for my $new_row (#transposed) {
for my $new_col (#{$new_row}) {
print $new_col, " ";
}
print "\n";
}
}
**********INPUT FILE******
1 2 3
4 5 6
7 8 9
********** EXPECTED OUTPUT FILE *******
1 4 7
2 5 8
3 6 9
******** GENERATED OUTPUT FILE *******
Currently couldn't able print anything. script shows the error
"can't use string ("1 4 7") as an array ref while "strict refs" in use
Reference:
used the following reference...
Transpose in perl
however in this reference example, array input lines are declared manually where as i am trying to process a array which is in a text file
could anybody help me where i did mistake?
Many Thanks
You did have to split input line as #dland suggested. But, there were a few other issues.
Here's the corrected code [please pardon the gratuitous style cleanup]:
#! /usr/bin/perl
use strict;
use warnings;
use autodie;
open my $fh, '<',"op.txt" || die "$!";
open my $wh , '>',"pwl.txt" || die "$!";
my #rows;
while (my $line = <$fh>) {
my #line = split(" ",$line);
push(#rows,\#line);
}
close($fh);
my #transposed;
for my $row (#rows) {
push(#transposed,[]);
}
my $rowidx = -1;
for my $rowptr (#rows) {
++$rowidx;
my $colidx = -1;
for my $rowval (#$rowptr) {
++$colidx;
###printf("R=%d C=%d\n",$rowidx,$colidx);
my $colptr = $transposed[$colidx];
$colptr->[$rowidx] = $rowval;
}
}
for my $new_row (#transposed) {
for my $new_col (#$new_row) {
print $wh $new_col, " ";
}
print $wh "\n";
}
close($wh);
Note: It's slightly harder to transpose a non-square matrix. The above code may need to be extended a bit for that.
You're trying to shove a scalar into an array:
my #row = $line;
I think what you really want is to split on spaces:
my #row = split / /, $line;
adding my #row =map [ split], $line to my initial code is helping to print the data to pwl.txt.
however its not printing side by side.. instead it is printing to new line.
I guess because of this Mr.Borodin didn't include matrix in side while loop!
1
2
3
4
5
6
7
8
9
Here's a simpler way of doing this. It assumes all the rows are of the same length, and that all the lines in the file contain data -- i.e. there are no blank lines
The name of the input file is expected as a parameter on the command line, and the output is sent to STDOUT so it can be redirected on the command line. For instance
perl transpose.pl op.txt > pwl.txt
use strict;
use warnings 'all';
my #matrix = map [ split ], <>;
print "#$_\n" for #matrix;
print "\n";
my #transpose;
for my $i ( 0 .. $#{ $matrix[0] } ) {
$transpose[$i] = [ map { $_->[$i] } #matrix ]
}
print "#$_\n" for #transpose;
print "\n";
output
1 2 3
4 5 6
7 8 9
1 4 7
2 5 8
3 6 9

Perl script to find Repeating patterns and number of occurence in a file? [closed]

Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 7 years ago.
Improve this question
I am looking for a Perl Script that will efficiently find repeating patterns and their number of occurrence in a file.
Sample File Input:
1
2
3
1
2
5
1
2
4
Sample output
The repeating Patterns are
1 - 3
2 - 3
1 2 - 3
I think you have to put a limit to the pattern size otherwise complexity will be a problem.
Given that P is the pattern size, N the file(list) length the complexity of my solution should be O(N*P)
my $window_size = 5;
my #input = qw ( 1 2 3 1 2 5 1 2 4 );
my %result;
my %windows;
foreach my $inp (#input) {
for my $win_size (1..$window_size){
push #{ $windows{$win_size} } , $inp;
shift #{ $windows{$win_size} } if scalar #{ $windows{$win_size} } > $win_size;
my $win_string = join(' ', #{ $windows{$win_size} });
$result{$win_string} += 1 if scalar #{ $windows{$win_size} } == $win_size;
}
}
foreach (sort { length $a <=> length $b } keys %result) {
print "$_ \t\t $result{$_}\n";
}
Here is a way by using hash. Following code will give you the repeating patterns and their number of occurrence in a file:
#!/usr/bin/perl
use warnings;
use strict;
my %count;
open my $fh, "<", "abc.txt" or die $!;
while(my $line = <$fh>)
{
chomp $line;
$count{$line} += 1;
}
close $fh;
foreach my $pattern (sort keys %count)
{
next if ($count{$pattern} == 1);
print $pattern . " - " . $count{$pattern} . "\n";
}
Output:
1 - 3
2 - 3

Analyzing a txt list in perl [closed]

Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Questions asking for code must demonstrate a minimal understanding of the problem being solved. Include attempted solutions, why they didn't work, and the expected results. See also: Stack Overflow question checklist
Closed 8 years ago.
Improve this question
I am trying to analyze a list of coordinates. The txt file is set up like this:
ID START END
A 10 20
B 15 17
C 20 40
How would I check this dataset to check if START and END is included within a user-specified region, e.g. START=10 END=15?
Any help greatly appreciated
// edit //
if(#AGRV != 4) {
print STDOUT "Searches genomic data for CNV within range. \n";
print STDOUT "CNV FILE FORMAT: <ID><CHR>BPS><BPE><AGE><etc...> \n";
print STDOUT "USAGE: [CNVLIST][CHR][BPS][BPE][OUTFILE] \n";
exit;
}
open(CNVLIST,"<$ARGV[0]");
open(OUTFILE,">$ARGV[3]");
$BPS = $ARGV[1];
$BPE = $ARGV[2];
#put CNV file in hash table
$line = <CNVFILE>;
while($line = <CNVFILE>) {
chomp $line;
($Cchr,$CS,$CE,$CID) = split(/\t/,$line);
}
I need to look through each line and find if the start/end lies within the user specified range.
it is unclear whether you can assume that the ID will never overlap with each other, but assuming it won't , you can use hash to store the lines that are within the range. If it's possible that the ID might overlap, I think you can push #{$result{id}}, [$start, $end]; but that'll make the data structure a bit more complicated.
#!/usr/bin/perl
use strict;
use warnings;
use Data::Dumper;
my $in_file = "input.txt";
# User-specified region
my $range_start = 10;
my $range_end = 15;
open my $fh, $in_file or die $!;
my %result;
while (<$fh>) {
my ($id, $start, $end) = split " ", $_;
next unless $start =~ /\d/;
# Swap if START is larger than END
($start, $end) = ($end, $start) if $start > $end;
$result{$id} = [$start, $end]
if $start >= $range_start and $end <= $range_end;
}
print Dumper(%result);
You can split() each line and check second and third field:
#!/usr/bin/env perl
use strict;
use warnings;
my ($start, $end) = (shift, shift);
die if $start > $end;
## Skip header
<>;
while ( <> ) {
chomp;
my #f = split;
if ( $f[1] <= $start && $f[2] >= $end ) {
printf qq|%s\n|, $_;
}
}
It accepts three arguments, the first one is the start region, the second one is the end region and the last one is the file to process. It prints to output all lines that pass the condition.
Run it like:
perl script.pl 10 15 infile
That yields:
A 10 20

perl extract information from several files in folders into the specific files

I'm just trying to extract of daily data to analyze yearly something.
So, I made a code for searching folder and files.
After that I wanna extract curtain lines in several files that has same name in the middle.
When I done my work, I realize that there are only one day information left
daily data is grid format like this.
ncols 751
nrows 601
xllcorner 124.5
yllcorner 33.
cellsize 0.01
nodata_value -99
-99.0 -99.0 -99.0 -99.0 -99.0
I wanna get the result like this with my code.
1.txt (2011)
10 10 10 10 10 4 4 3 2
5 4 3 2 10 4 4 3 2
1 1 10 10 10 10 10 10
2.txt (2012)
3 4 2 10 10 4 4 3 2
5 4 3 2 10 4 4 3 2
1 1 10 10 10 10 10 10
use 5.010;
use warnings;
if( $#ARGV < 0 )
{ die "need folder.\n"; }
$dirName = shift(#ARGV);
local($i);
#rutine
&readSubDir($dirName);
sub readSubDir
{
if(!opendir(dirHandle, $_[0]))
{
print "$_[0] Failed opening.\n";
return 0;
}
local(#files) = readdir(dirHandle);
local($i);
local($newFile);
local(#dironly);
local(#fileonly);
for($i = 0; $i <= $#files; $i++)
{
$newFile = $_[0]."\\".$files[$i];
if(-d $newFile)
{
push(#dironly, $files[$i]);
}
elsif(-f $newFile)
{
push(#fileonly, $files[$i]);
}
else
{}
}
#files = #dironly;
push(#files, #fileonly);
closedir dirHandle;
my $cnt = 1;
my $b = 2011;
for($i =0; $i <= $#files; $i++){
$newFile = $_[0]."\\".$files[$i];
if(-f $newFile){
open(fileHandle, $newFile)|| die "Cannot open 개체 \n";
my($dir, $file, $ext) = ($newFile =~ m|^(.*\\)(.*)(\..*)$| );
if (substr($file,17,4) eq $b){
while(<fileHandle>){
if($. == 7){
my $filename = $cnt.'.txt';
open OUT, ">$filename" or die "Failed to create $filename";
print OUT $_;
}
}
close(fileHandle);
}
elsif (substr($file,17,4) eq $b+1){
$b++;
$cnt++;
while(<fileHandle>){
if($. == 7){
my $filename = $cnt.'.txt';
open OUT, ">$filename" or die "Failed to create $filename";
print OUT $_;
}
}
close(fileHandle);
}
}
close(OUT);
}
}
The question really isn't clear exactly what you're trying to accomplish, as the information in the daily file data example doesn't match any of the data in the output examples. However, from looking at your code I think I get what you're trying to do and I think your problem is occurring when you open the output file to store the lines you extracted. You're opening the file with >, which indicates you're opening the file for output, but it will also overwrite the file if it already exists. So your code is just overwriting the same file over and over and only the information in the last file will be saved. You need to open the file in append mode using >>. So your code should look similar to the following:
open OUT, ">>$filename" or die "Failed to create $filename";