Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Add x^2 to every "nonzero" coefficient with sed/awk

Tags:

bash

sed

awk

ubuntu

I have to write, as easy as possible, a script or command which has to use awk or/and sed. Input file:

23 12 0 33
3 4 19

1st line n=3
2nd line n=2
In each line of file we have string of numbers. Each number is coefficient and we have to add x^n where n is the highest power (sum of spaces between numbers in each line (no space after last number in each line)) and if we have "0" in our string we have to skip it. So for that input we will have output like:

23x^3+12x^2+33
3x^2+4x+19

Please help me to write a short script solving that problem. Thank you so much for your time and all the help :) My idea:

linescount=$(cat numbers|wc -l)
linecounter=1
While[linecounter<=linescount];
do
i=0
for i in spaces=$(cat numbers|sed 1p | sed " " )
do
sed -i 's/ /x^spaces/g'
i=($(i=i-1))
done
linecounter=($(linecounter=linecounter-1))
done
like image 293
Sz3jdii Avatar asked Apr 06 '18 23:04

Sz3jdii


4 Answers

Following awk may help you on same too.

awk '{for(i=1;i<=NF;i++){if($i!="" && $i){val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))} else {pointer++}};if(val){print val};val=""} pointer==NF{print;} {pointer=""}'  Input_file

Adding a non-one liner form of solution too here.

awk '
{
  for(i=1;i<=NF;i++){
    if($i!="" && $i){
       val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))}
    else            {
       pointer++}};
    if(val)         {
       print val};
  val=""
}
pointer==NF         {
  print}
{
  pointer=""
}
'  Input_file


EDIT: Adding explanation too here for better understanding of OP and all people's learning here.

awk '
{
  for(i=1;i<=NF;i++){                                              ##Starting a for loop from variable 1 to till the value of NF here.
    if($i!="" && $i){                                              ##checking if variable i value is NOT NULL then do following.
       val=(val?val "+" $i:$i)(NF-i==0?"":(NF-i==1?"x":"x^"NF-i))} ##creating variable val here and putting conditions here if val is NULL then
                                                                   ##simply take value of that field else concatenate the value of val with its
                                                                   ##last value. Second condition is to check if last field of line is there then
                                                                   ##keep it like that else it is second last then print "x" along with it else keep
                                                                   ##that "x^" field_number-1 with it.
    else            {                                              ##If a field is NULL in current line then come here.
       pointer++}};                                                ##Increment the value of variable named pointer here with 1 each time it comes here.
    if(val)         {                                              ##checking if variable named val is NOT NULL here then do following.
       print val};                                                 ##Print the value of variable val here.
  val=""                                                           ##Nullifying the variable val here.
}
pointer==NF         {                                              ##checking condition if pointer value is same as NF then do following.
  print}                                                           ##Print the current line then, seems whole line is having zeros in it.
{
  pointer=""                                                       ##Nullifying the value of pointer here.
}
' Input_file                                                       ##Mentioning Input_file name here.
like image 143
RavinderSingh13 Avatar answered Nov 19 '22 16:11

RavinderSingh13


Offering a Perl solution since it has some higher level constucts than bash that make the code a little simpler:

use strict;
use warnings; 

use feature qw(say);

my @terms;
while (my $line = readline(*DATA)) {
  chomp($line); 

  my $degree = () = $line =~ / /g;
  my @coefficients = split / /, $line;

  my @terms; 
  while ($degree >= 0) {
    my $coefficient = shift @coefficients;
    next if $coefficient == 0;

    push @terms, $degree > 1 
      ? "${coefficient}x^$degree" 
      : $degree > 0 
          ? "${coefficient}x" 
          : $coefficient;
  } 
  continue {
    $degree--;
  }

  say join '+', @terms;
}

__DATA__
23 12 0 33
3 4 19

Example output:

hunter@eros  ~  perl test.pl
23x^3+12x^2+33
3x^2+4x+19

Any information you want on any of the builtin functions used above: readline, chomp, push, shift, split, say, and join can be found in perldoc with perldoc -f <function-name>

like image 45
Hunter McMillen Avatar answered Nov 19 '22 16:11

Hunter McMillen


$ cat a.awk
function print_term(i) {
    # Don't print zero terms:                                                                                                                                                 
    if (!$i) return;

    # Print a "+" unless this is the first term:                                                                                                                               
    if (!first) { printf " + " }

    # If it's the last term, just print the number:                                                                                                                            
    if (i == NF) printf "%d", $i

    # Leave the coefficient blank if it's 1:                                                                                                                                    
    coef = ($i == 1 ? "" : $i)

    # If it's the penultimate term, just print an 'x' (not x^1):                                                                                                               
    if (i == NF-1) printf "%sx", coef

    # Print a higher-order term:
    if (i < NF-1) printf "%sx^%s", coef, NF - i
    first = 0
}

{
  first = 1

  # print all the terms:
  for (i=1; i<=NF; ++i) print_term(i)

  # If we never printed any terms, print a "0":
  print first ? 0 : ""
}

Example input and output:

$ cat file
23 12 0 33
3 4 19
0 0 0
0 1 0 1
17

$ awk -f a.awk file
23x^3 + 12x^2 + 33
3x^2 + 4x + 19
0
x^2 + 1
17
like image 2
jas Avatar answered Nov 19 '22 17:11

jas


$ cat ip.txt
23 12 0 33
3 4 19
5 3 0
34 01 02

$ # mapping each element except last to add x^n
$ # -a option will auto-split input on whitespaces, content in @F array
$ # $#F will give index of last element (indexing starts at 0)
$ # $i>0 condition check to prevent x^0 for last element
$ perl -lane '$i=$#F; print join "+", map {$i>0 ? $_."x^".$i-- : $_} @F' ip.txt
23x^3+12x^2+0x^1+33
3x^2+4x^1+19
5x^2+3x^1+0
34x^2+01x^1+02

$ # with post processing
$ perl -lape '$i=$#F; $_ = join "+", map {$i>0 ? $_."x^".$i-- : $_} @F;
              s/\+0(x\^\d+)?\b|x\K\^1\b//g' ip.txt 
23x^3+12x^2+33
3x^2+4x+19
5x^2+3x
34x^2+01x+02
like image 2
Sundeep Avatar answered Nov 19 '22 18:11

Sundeep